Merge "Modify onHostEndpointDisconnected to always return OK"
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 30e88b5..7db50d5 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -49,9 +49,6 @@
             ],
         },
         ndk: {
-            vndk: {
-                enabled: true,
-            },
             apex_available: [
                 "//apex_available:platform",
                 "com.android.bluetooth",
@@ -78,6 +75,7 @@
         "android/hardware/audio/core/IModule.aidl",
         "android/hardware/audio/core/IStreamIn.aidl",
         "android/hardware/audio/core/IStreamOut.aidl",
+        "android/hardware/audio/core/ModuleDebug.aidl",
     ],
     imports: [
         "android.hardware.audio.common-V1",
@@ -85,15 +83,12 @@
     ],
     stability: "vintf",
     backend: {
+        // The C++ backend is disabled transitively due to use of FMQ.
+        cpp: {
+            enabled: false,
+        },
         java: {
             platform_apis: true,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
-    versions: [
-    ],
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
index 33e8290..f8bc2c7 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
@@ -34,11 +34,15 @@
 package android.hardware.audio.core;
 @VintfStability
 interface IModule {
+  void setModuleDebug(in android.hardware.audio.core.ModuleDebug debug);
+  android.media.audio.common.AudioPort connectExternalDevice(in android.media.audio.common.AudioPort templateIdAndAdditionalData);
+  void disconnectExternalDevice(int portId);
   android.hardware.audio.core.AudioPatch[] getAudioPatches();
   android.media.audio.common.AudioPort getAudioPort(int portId);
   android.media.audio.common.AudioPortConfig[] getAudioPortConfigs();
   android.media.audio.common.AudioPort[] getAudioPorts();
   android.hardware.audio.core.AudioRoute[] getAudioRoutes();
+  android.hardware.audio.core.AudioRoute[] getAudioRoutesForAudioPort(int portId);
   android.hardware.audio.core.IStreamIn openInputStream(int portConfigId, in android.hardware.audio.common.SinkMetadata sinkMetadata);
   android.hardware.audio.core.IStreamOut openOutputStream(int portConfigId, in android.hardware.audio.common.SourceMetadata sourceMetadata, in @nullable android.media.audio.common.AudioOffloadInfo offloadInfo);
   android.hardware.audio.core.AudioPatch setAudioPatch(in android.hardware.audio.core.AudioPatch requested);
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl
new file mode 100644
index 0000000..80ee185
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.core;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable ModuleDebug {
+  boolean simulateDeviceConnections;
+}
diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index d47ea3c..802cb2f 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -22,6 +22,7 @@
 import android.hardware.audio.core.AudioRoute;
 import android.hardware.audio.core.IStreamIn;
 import android.hardware.audio.core.IStreamOut;
+import android.hardware.audio.core.ModuleDebug;
 import android.media.audio.common.AudioOffloadInfo;
 import android.media.audio.common.AudioPort;
 import android.media.audio.common.AudioPortConfig;
@@ -44,6 +45,116 @@
 @VintfStability
 interface IModule {
     /**
+     * Sets debugging configuration for the HAL module. This method is only
+     * called during xTS testing and is intended for validating the aspects of
+     * the HAL module behavior that would otherwise require human intervention.
+     *
+     * The HAL module must throw an error if there is an attempt to change
+     * the debug behavior for the aspect which is currently in use.
+     *
+     * @param debug The debug options.
+     * @throws EX_ILLEGAL_STATE If the flag(s) being changed affect functionality
+     *                          which is currently in use.
+     */
+    void setModuleDebug(in ModuleDebug debug);
+
+    /**
+     * Set a device port of an external device into connected state.
+     *
+     * This method is used to inform the HAL module that an external device has
+     * been connected to a device port selected using the 'id' field of the
+     * input AudioPort parameter. This device port must have dynamic profiles
+     * (an empty list of profiles). This port is further referenced to as "port
+     * template" because it acts as a template for creating a new instance of a
+     * "connected" device port which gets returned from this method.
+     *
+     * The input AudioPort parameter may contain any additional data obtained by
+     * the system side from other subsystems. The nature of data depends on the
+     * type of the connection. For example, for point-to-multipoint external
+     * device connections, the input parameter may contain the address of the
+     * connected external device. Another example is EDID information for HDMI
+     * connections (ExtraAudioDescriptor), which can be provided by the HDMI-CEC
+     * HAL module.
+     *
+     * It is the responsibility of the HAL module to query audio profiles
+     * supported by the connected device and return them as part of the returned
+     * AudioPort instance. In the case when the HAL is unable to query the
+     * external device, an error must be thrown.
+     *
+     * Thus, the returned audio port instance is the result of combining the
+     * following information:
+     *  - a unique port ID generated by the HAL module;
+     *  - static information from the port template;
+     *  - list of audio profiles supported by the connected device;
+     *  - additional data from the input AudioPort parameter.
+     *
+     * The HAL module must also update the list of audio routes to include the
+     * ID of the instantiated connected device port. Normally, the connected
+     * port allows the same routing as the port template.
+     *
+     * Also see notes on 'ModuleDebug.simulateDeviceConnections'.
+     *
+     * The following protocol is used by HAL module client for handling
+     * connection of an external device:
+     *  1. Obtain the list of device ports and their IDs via 'getAudioPorts'
+     *     method. Select the appropriate port template using
+     *     AudioDeviceDescription ('ext.device' field of AudioPort).
+     *  2. Combine the ID of the port template with any additional data and call
+     *     'connectExternalDevice'. The HAL module returns a new instance of
+     *     AudioPort created using the rules explained above. Both
+     *     'getAudioPort' and 'getAudioPorts' methods will be returning the same
+     *     information for this port until disconnection.
+     *  3. Configure the connected port with one of supported profiles using
+     *     'setAudioPortConfig'.
+     *  4. Query the list of AudioRoutes for the new AudioPort using
+     *     'getAudioRoutesForAudioPort' or 'getAudioRoutes' methods.
+     *
+     * External devices are distinguished by the connection type and device
+     * address. Calling this method multiple times to inform about connection of
+     * the same external device without disconnecting it first is an error.
+     *
+     * The HAL module must perform validation of the input parameter and throw
+     * an error if it is lacking required information, for example, when no
+     * device address is specified for a point-to-multipoint external device
+     * connection.
+     *
+     * Handling of a disconnect is done in a reverse order:
+     *  1. Reset port configuration using the 'resetAudioPortConfig' method.
+     *  2. Release the connected device port by calling the 'disconnectExternalDevice'
+     *     method. This also removes the audio routes associated with this
+     *     device port.
+     *
+     * @return New instance of an audio port for the connected external device.
+     * @param templateIdAndAdditionalData Specifies port template ID and any
+     *                                    additional data.
+     * @throws EX_ILLEGAL_ARGUMENT In the following cases:
+     *                             - If the template port can not be found by the ID.
+     *                             - If the template is not a device port, or
+     *                               it does not have dynamic profiles.
+     *                             - If the input parameter is lacking required
+     *                               information.
+     * @throws EX_ILLEGAL_STATE In the following cases:
+     *                          - If the HAL module is unable to query audio profiles.
+     *                          - If the external device has already been connected.
+     */
+    AudioPort connectExternalDevice(in AudioPort templateIdAndAdditionalData);
+
+    /**
+     * Set a device port of a an external device into disconnected state.
+     *
+     * This method is used to inform the HAL module that an external device has
+     * been disconnected. The 'portId' must be of a connected device port
+     * instance previously instantiated using the 'connectExternalDevice'
+     * method.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT In the following cases:
+     *                             - If the port can not be found by the ID.
+     *                             - If this is not a connected device port.
+     * @throws EX_ILLEGAL_STATE If the port has active configurations.
+     */
+    void disconnectExternalDevice(int portId);
+
+    /**
      * Return all audio patches of this module.
      *
      * Returns a list of audio patches, that is, established connections between
@@ -57,12 +168,10 @@
      * Return the current state of the audio port.
      *
      * Using the port ID provided on input, returns the current state of the
-     * audio port. For device port representing a connection to some external
-     * device, e.g. over HDMI or USB, currently supported audio profiles and
-     * extra audio descriptors may change.
-     *
-     * For all other audio ports it must be the same configuration as returned
-     * for this port ID by 'getAudioPorts'.
+     * audio port. The values of the AudioPort structure must be the same as
+     * currently returned by the 'getAudioPorts' method. The 'getAudioPort'
+     * method is provided to reduce overhead in the case when the client needs
+     * to check the state of one port only.
      *
      * @return The current state of an audio port.
      * @param portId The ID of the audio port.
@@ -87,33 +196,45 @@
     AudioPortConfig[] getAudioPortConfigs();
 
     /**
-     * Return all audio ports provided by this module.
+     * Return the current state of all audio ports provided by this module.
      *
-     * Returns a list of all mix ports and device ports provided by this
-     * module. Each returned port must have a unique ID within this module
-     * ('AudioPort.id' field). The returned list must not change during
-     * the lifetime of the IModule instance. For audio ports with dynamic
-     * profiles (changing depending on external devices being connected
-     * to the system) an empty list of profiles must be returned. The list
-     * of currently supported audio profiles is obtained from 'getAudioPort'
-     * method.
+     * Returns a list of all mix ports and device ports provided by this HAL
+     * module, reflecting their current states. Each returned port must have a
+     * unique ID within this module ('AudioPort.id' field). The list also
+     * includes "connected" ports created using 'connectExternalDevice' method.
      *
      * @return The list of audio ports.
      */
     AudioPort[] getAudioPorts();
 
     /**
-     * Return all audio routes of this module.
+     * Return all current audio routes of this module.
      *
-     * Returns a list of audio routes, that is, allowed connections between
-     * audio ports. The returned list must not change during the lifetime of the
-     * IModule instance.
+     * Returns the current list of audio routes, that is, allowed connections
+     * between audio ports. The list can change when new device audio ports
+     * get created as a result of connecting or disconnecting of external
+     * devices.
      *
      * @return The list of audio routes.
      */
     AudioRoute[] getAudioRoutes();
 
     /**
+     * Return audio routes related to the specified audio port.
+     *
+     * Returns the list of audio routes that include the specified port ID
+     * as a source or as a sink. The returned list is a subset of the result
+     * returned by the 'getAudioRoutes' method, filtered by the port ID.
+     * An empty list can be returned, indicating that the audio port can not
+     * be used for creating audio patches.
+     *
+     * @return The list of audio routes.
+     * @param portId The ID of the audio port.
+     * @throws EX_ILLEGAL_ARGUMENT If the port can not be found by the ID.
+     */
+    AudioRoute[] getAudioRoutesForAudioPort(int portId);
+
+    /**
      * Open an input stream using an existing audio mix port configuration.
      *
      * The audio port configuration ID must be obtained by calling
@@ -161,6 +282,8 @@
      * @throws EX_ILLEGAL_ARGUMENT In the following cases:
      *                             - If the port config can not be found by the ID.
      *                             - If the port config is not of an output mix port.
+     *                             - If the offload info is not provided for an offload
+     *                               port configuration.
      * @throws EX_ILLEGAL_STATE In the following cases:
      *                          - If the port config already has a stream opened on it.
      *                          - If the limit on the open stream count for the port has
@@ -230,6 +353,10 @@
      * parameter. The framework can then set the suggested configuration on a
      * subsequent retry call to this method.
      *
+     * Device ports with dynamic audio profiles (an empty list of profiles)
+     * can not be used with this method. The list of profiles must be filled in
+     * as a result of calling 'connectExternalDevice' method.
+     *
      * @return Whether the requested configuration has been applied.
      * @param requested Requested audio port configuration.
      * @param suggested Same as requested configuration, if it was applied.
@@ -241,7 +368,7 @@
      *                             - If the port can not be found by the port ID.
      *                             - If it is not possible to generate a suggested port
      *                               configuration, for example, if the port only has dynamic
-     *                               profiles and they are currently empty.
+     *                               profiles.
      */
     boolean setAudioPortConfig(in AudioPortConfig requested, out AudioPortConfig suggested);
 
diff --git a/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl b/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl
new file mode 100644
index 0000000..858a9bd
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+/**
+ * This structure contains flags used for enabling various debugging aspects
+ * in a HAL module. By default, all debugging aspects are turned off. They
+ * can be enabled during xTS tests for functionality that, for example, would
+ * otherwise require human intervention (e.g. connection of external devices).
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable ModuleDebug {
+    /**
+     * When set to 'true', HAL module must simulate connection of external
+     * devices. An external device becomes 'connected' after a call to
+     * IModule.connectExternalDevice, simulation of connection requires:
+     *  - provision of at least one non-dynamic device port profile on
+     *    connection (as if it was retrieved from a connected device);
+     *  - simulating successful application of port configurations for reported
+     *    profiles.
+     */
+    boolean simulateDeviceConnections;
+}
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 0a6fe60..ad1d9c7 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -13,6 +13,8 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
+        "libstagefright_foundation",
+        "android.media.audio.common.types-V1-ndk",
         "android.hardware.audio.core-V1-ndk",
     ],
     export_include_dirs: ["include"],
@@ -36,6 +38,8 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
+        "libstagefright_foundation",
+        "android.media.audio.common.types-V1-ndk",
         "android.hardware.audio.core-V1-ndk",
     ],
     static_libs: [
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index 1104caa..f5d679b 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -16,14 +16,16 @@
 
 #include <aidl/android/media/audio/common/AudioChannelLayout.h>
 #include <aidl/android/media/audio/common/AudioDeviceType.h>
+#include <aidl/android/media/audio/common/AudioFormatDescription.h>
 #include <aidl/android/media/audio/common/AudioFormatType.h>
 #include <aidl/android/media/audio/common/AudioIoFlags.h>
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
+#include <media/stagefright/foundation/MediaDefs.h>
 
-#include "aidl/android/media/audio/common/AudioFormatDescription.h"
 #include "core-impl/Configuration.h"
 
 using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioDeviceDescription;
 using aidl::android::media::audio::common::AudioDeviceType;
 using aidl::android::media::audio::common::AudioFormatDescription;
 using aidl::android::media::audio::common::AudioFormatType;
@@ -41,22 +43,38 @@
 
 namespace aidl::android::hardware::audio::core::internal {
 
+static void fillProfile(AudioProfile* profile, const std::vector<int32_t>& channelLayouts,
+                        const std::vector<int32_t>& sampleRates) {
+    for (auto layout : channelLayouts) {
+        profile->channelMasks.push_back(
+                AudioChannelLayout::make<AudioChannelLayout::layoutMask>(layout));
+    }
+    profile->sampleRates.insert(profile->sampleRates.end(), sampleRates.begin(), sampleRates.end());
+}
+
 static AudioProfile createProfile(PcmType pcmType, const std::vector<int32_t>& channelLayouts,
                                   const std::vector<int32_t>& sampleRates) {
     AudioProfile profile;
     profile.format.type = AudioFormatType::PCM;
     profile.format.pcm = pcmType;
-    for (auto layout : channelLayouts) {
-        profile.channelMasks.push_back(
-                AudioChannelLayout::make<AudioChannelLayout::layoutMask>(layout));
-    }
-    profile.sampleRates.insert(profile.sampleRates.end(), sampleRates.begin(), sampleRates.end());
+    fillProfile(&profile, channelLayouts, sampleRates);
     return profile;
 }
 
-static AudioPortExt createDeviceExt(AudioDeviceType devType, int32_t flags) {
+static AudioProfile createProfile(const std::string& encodingType,
+                                  const std::vector<int32_t>& channelLayouts,
+                                  const std::vector<int32_t>& sampleRates) {
+    AudioProfile profile;
+    profile.format.encoding = encodingType;
+    fillProfile(&profile, channelLayouts, sampleRates);
+    return profile;
+}
+
+static AudioPortExt createDeviceExt(AudioDeviceType devType, int32_t flags,
+                                    std::string connection = "") {
     AudioPortDeviceExt deviceExt;
     deviceExt.device.type.type = devType;
+    deviceExt.device.type.connection = std::move(connection);
     deviceExt.flags = flags;
     return AudioPortExt::make<AudioPortExt::Tag::device>(deviceExt);
 }
@@ -102,8 +120,66 @@
     return route;
 }
 
+// Configuration:
+//
+// Device ports:
+//  * "Null", OUT_SPEAKER, default
+//    - no profiles specified
+//  * "Loopback Out", OUT_SUBMIX
+//    - profile PCM 24-bit; STEREO; 48000
+//  * "USB Out", OUT_DEVICE, CONNECTION_USB
+//    - no profiles specified
+//  * "Zero", IN_MICROPHONE, default
+//    - no profiles specified
+//  * "Loopback In", IN_SUBMIX
+//    - profile PCM 24-bit; STEREO; 48000
+//  * "USB In", IN_DEVICE, CONNECTION_USB
+//    - no profiles specified
+//
+// Mix ports:
+//  * "primary output", PRIMARY, 1 max open, 1 max active stream
+//    - profile PCM 16-bit; MONO, STEREO; 44100, 48000
+//    - profile PCM 24-bit; MONO, STEREO; 44100, 48000
+//  * "compressed offload", DIRECT|COMPRESS_OFFLOAD|NON_BLOCKING, 1 max open, 1 max active stream
+//    - profile MP3; MONO, STEREO; 44100, 48000
+//  * "loopback output", stream count unlimited
+//    - profile PCM 24-bit; STEREO; 48000
+//  * "primary input", 2 max open, 2 max active streams
+//    - profile PCM 16-bit; MONO, STEREO, FRONT_BACK;
+//        8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+//    - profile PCM 24-bit; MONO, STEREO, FRONT_BACK;
+//        8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+//  * "loopback input", stream count unlimited
+//    - profile PCM 24-bit; STEREO; 48000
+//
+// Routes:
+//  "primary out", "compressed offload" -> "Null"
+//  "primary out", "compressed offload" -> "USB Out"
+//  "loopback out" -> "Loopback Out"
+//  "Zero", "USB In" -> "primary input"
+//  "Loopback In" -> "loopback input"
+//
+// Initial port configs:
+//  * "Null" device port: PCM 24-bit; STEREO; 48000
+//  * "Zero" device port: PCM 24-bit; MONO; 48000
+//
+// Profiles for device port connected state:
+//  * USB Out":
+//    - profile PCM 16-bit; MONO, STEREO; 44100, 48000
+//    - profile PCM 24-bit; MONO, STEREO; 44100, 48000
+//  * USB In":
+//    - profile PCM 16-bit; MONO, STEREO; 44100, 48000
+//    - profile PCM 24-bit; MONO, STEREO; 44100, 48000
+//
 Configuration& getNullPrimaryConfiguration() {
     static Configuration configuration = []() {
+        const std::vector<AudioProfile> standardPcmAudioProfiles = {
+                createProfile(PcmType::INT_16_BIT,
+                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+                              {44100, 48000}),
+                createProfile(PcmType::INT_24_BIT,
+                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+                              {44100, 48000})};
         Configuration c;
 
         AudioPort nullOutDevice =
@@ -111,27 +187,31 @@
                            createDeviceExt(AudioDeviceType::OUT_SPEAKER,
                                            1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
         c.ports.push_back(nullOutDevice);
-
-        AudioPort primaryOutMix = createPort(c.nextPortId++, "primary output",
-                                             1 << static_cast<int32_t>(AudioOutputFlags::PRIMARY),
-                                             false, createPortMixExt(1, 1));
-        primaryOutMix.profiles.push_back(
-                createProfile(PcmType::INT_16_BIT,
-                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
-                              {44100, 48000}));
-        primaryOutMix.profiles.push_back(
-                createProfile(PcmType::INT_24_BIT,
-                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
-                              {44100, 48000}));
-        c.ports.push_back(primaryOutMix);
-
-        c.routes.push_back(createRoute({primaryOutMix.id}, nullOutDevice.id));
-
         c.initialConfigs.push_back(
                 createPortConfig(nullOutDevice.id, nullOutDevice.id, PcmType::INT_24_BIT,
                                  AudioChannelLayout::LAYOUT_STEREO, 48000, 0, false,
                                  createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0)));
 
+        AudioPort primaryOutMix = createPort(c.nextPortId++, "primary output",
+                                             1 << static_cast<int32_t>(AudioOutputFlags::PRIMARY),
+                                             false, createPortMixExt(1, 1));
+        primaryOutMix.profiles.insert(primaryOutMix.profiles.begin(),
+                                      standardPcmAudioProfiles.begin(),
+                                      standardPcmAudioProfiles.end());
+        c.ports.push_back(primaryOutMix);
+
+        AudioPort compressedOffloadOutMix =
+                createPort(c.nextPortId++, "compressed offload",
+                           1 << static_cast<int32_t>(AudioOutputFlags::DIRECT) |
+                                   1 << static_cast<int32_t>(AudioOutputFlags::COMPRESS_OFFLOAD) |
+                                   1 << static_cast<int32_t>(AudioOutputFlags::NON_BLOCKING),
+                           false, createPortMixExt(1, 1));
+        compressedOffloadOutMix.profiles.push_back(
+                createProfile(::android::MEDIA_MIMETYPE_AUDIO_MPEG,
+                              {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+                              {44100, 48000}));
+        c.ports.push_back(compressedOffloadOutMix);
+
         AudioPort loopOutDevice = createPort(c.nextPortId++, "Loopback Out", 0, false,
                                              createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0));
         loopOutDevice.profiles.push_back(
@@ -144,13 +224,22 @@
                 createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
         c.ports.push_back(loopOutMix);
 
-        c.routes.push_back(createRoute({loopOutMix.id}, loopOutDevice.id));
+        AudioPort usbOutDevice =
+                createPort(c.nextPortId++, "USB Out", 0, false,
+                           createDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
+                                           AudioDeviceDescription::CONNECTION_USB));
+        c.ports.push_back(usbOutDevice);
+        c.connectedProfiles[usbOutDevice.id] = standardPcmAudioProfiles;
 
         AudioPort zeroInDevice =
                 createPort(c.nextPortId++, "Zero", 0, true,
                            createDeviceExt(AudioDeviceType::IN_MICROPHONE,
                                            1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
         c.ports.push_back(zeroInDevice);
+        c.initialConfigs.push_back(
+                createPortConfig(zeroInDevice.id, zeroInDevice.id, PcmType::INT_24_BIT,
+                                 AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
+                                 createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0)));
 
         AudioPort primaryInMix =
                 createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(2, 2));
@@ -166,13 +255,6 @@
                               {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}));
         c.ports.push_back(primaryInMix);
 
-        c.routes.push_back(createRoute({zeroInDevice.id}, primaryInMix.id));
-
-        c.initialConfigs.push_back(
-                createPortConfig(zeroInDevice.id, zeroInDevice.id, PcmType::INT_24_BIT,
-                                 AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
-                                 createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0)));
-
         AudioPort loopInDevice = createPort(c.nextPortId++, "Loopback In", 0, true,
                                             createDeviceExt(AudioDeviceType::IN_SUBMIX, 0));
         loopInDevice.profiles.push_back(
@@ -185,6 +267,18 @@
                 createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
         c.ports.push_back(loopInMix);
 
+        AudioPort usbInDevice = createPort(c.nextPortId++, "USB In", 0, true,
+                                           createDeviceExt(AudioDeviceType::IN_DEVICE, 0,
+                                                           AudioDeviceDescription::CONNECTION_USB));
+        c.ports.push_back(usbInDevice);
+        c.connectedProfiles[usbInDevice.id] = standardPcmAudioProfiles;
+
+        c.routes.push_back(
+                createRoute({primaryOutMix.id, compressedOffloadOutMix.id}, nullOutDevice.id));
+        c.routes.push_back(
+                createRoute({primaryOutMix.id, compressedOffloadOutMix.id}, usbOutDevice.id));
+        c.routes.push_back(createRoute({loopOutMix.id}, loopOutDevice.id));
+        c.routes.push_back(createRoute({zeroInDevice.id, usbInDevice.id}, primaryInMix.id));
         c.routes.push_back(createRoute({loopInDevice.id}, loopInMix.id));
 
         c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end());
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index e0a68a5..5b4d48a 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -18,7 +18,6 @@
 #include <set>
 
 #define LOG_TAG "AHAL_Module"
-#define LOG_NDEBUG 0
 #include <android-base/logging.h>
 
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
@@ -81,6 +80,7 @@
     }
     return false;
 }
+
 }  // namespace
 
 void Module::cleanUpPatch(int32_t patchId) {
@@ -135,6 +135,154 @@
     do_insert(patch.sinkPortConfigIds);
 }
 
+ndk::ScopedAStatus Module::setModuleDebug(
+        const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) {
+    LOG(DEBUG) << __func__ << ": old flags:" << mDebug.toString()
+               << ", new flags: " << in_debug.toString();
+    if (mDebug.simulateDeviceConnections != in_debug.simulateDeviceConnections &&
+        !mConnectedDevicePorts.empty()) {
+        LOG(ERROR) << __func__ << ": attempting to change device connections simulation "
+                   << "while having external devices connected";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    mDebug = in_debug;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdAndAdditionalData,
+                                                 AudioPort* _aidl_return) {
+    const int32_t templateId = in_templateIdAndAdditionalData.id;
+    auto& ports = getConfig().ports;
+    AudioPort connectedPort;
+    {  // Scope the template port so that we don't accidentally modify it.
+        auto templateIt = findById<AudioPort>(ports, templateId);
+        if (templateIt == ports.end()) {
+            LOG(ERROR) << __func__ << ": port id " << templateId << " not found";
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        if (templateIt->ext.getTag() != AudioPortExt::Tag::device) {
+            LOG(ERROR) << __func__ << ": port id " << templateId << " is not a device port";
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        if (!templateIt->profiles.empty()) {
+            LOG(ERROR) << __func__ << ": port id " << templateId
+                       << " does not have dynamic profiles";
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        auto& templateDevicePort = templateIt->ext.get<AudioPortExt::Tag::device>();
+        if (templateDevicePort.device.type.connection.empty()) {
+            LOG(ERROR) << __func__ << ": port id " << templateId << " is permanently attached";
+            return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+        }
+        // Postpone id allocation until we ensure that there are no client errors.
+        connectedPort = *templateIt;
+        connectedPort.extraAudioDescriptors = in_templateIdAndAdditionalData.extraAudioDescriptors;
+        const auto& inputDevicePort =
+                in_templateIdAndAdditionalData.ext.get<AudioPortExt::Tag::device>();
+        auto& connectedDevicePort = connectedPort.ext.get<AudioPortExt::Tag::device>();
+        connectedDevicePort.device.address = inputDevicePort.device.address;
+        LOG(DEBUG) << __func__ << ": device port " << connectedPort.id << " device set to "
+                   << connectedDevicePort.device.toString();
+        // Check if there is already a connected port with for the same external device.
+        for (auto connectedPortId : mConnectedDevicePorts) {
+            auto connectedPortIt = findById<AudioPort>(ports, connectedPortId);
+            if (connectedPortIt->ext.get<AudioPortExt::Tag::device>().device ==
+                connectedDevicePort.device) {
+                LOG(ERROR) << __func__ << ": device " << connectedDevicePort.device.toString()
+                           << " is already connected at the device port id " << connectedPortId;
+                return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+            }
+        }
+    }
+
+    if (!mDebug.simulateDeviceConnections) {
+        // In a real HAL here we would attempt querying the profiles from the device.
+        LOG(ERROR) << __func__ << ": failed to query supported device profiles";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+
+    connectedPort.id = ++getConfig().nextPortId;
+    mConnectedDevicePorts.insert(connectedPort.id);
+    LOG(DEBUG) << __func__ << ": template port " << templateId << " external device connected, "
+               << "connected port ID " << connectedPort.id;
+    auto& connectedProfiles = getConfig().connectedProfiles;
+    if (auto connectedProfilesIt = connectedProfiles.find(templateId);
+        connectedProfilesIt != connectedProfiles.end()) {
+        connectedPort.profiles = connectedProfilesIt->second;
+    }
+    ports.push_back(connectedPort);
+    *_aidl_return = std::move(connectedPort);
+
+    std::vector<AudioRoute> newRoutes;
+    auto& routes = getConfig().routes;
+    for (auto& r : routes) {
+        if (r.sinkPortId == templateId) {
+            AudioRoute newRoute;
+            newRoute.sourcePortIds = r.sourcePortIds;
+            newRoute.sinkPortId = connectedPort.id;
+            newRoute.isExclusive = r.isExclusive;
+            newRoutes.push_back(std::move(newRoute));
+        } else {
+            auto& srcs = r.sourcePortIds;
+            if (std::find(srcs.begin(), srcs.end(), templateId) != srcs.end()) {
+                srcs.push_back(connectedPort.id);
+            }
+        }
+    }
+    routes.insert(routes.end(), newRoutes.begin(), newRoutes.end());
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::disconnectExternalDevice(int32_t in_portId) {
+    auto& ports = getConfig().ports;
+    auto portIt = findById<AudioPort>(ports, in_portId);
+    if (portIt == ports.end()) {
+        LOG(ERROR) << __func__ << ": port id " << in_portId << " not found";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    if (portIt->ext.getTag() != AudioPortExt::Tag::device) {
+        LOG(ERROR) << __func__ << ": port id " << in_portId << " is not a device port";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    if (mConnectedDevicePorts.count(in_portId) == 0) {
+        LOG(ERROR) << __func__ << ": port id " << in_portId << " is not a connected device port";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    auto& configs = getConfig().portConfigs;
+    auto& initials = getConfig().initialConfigs;
+    auto configIt = std::find_if(configs.begin(), configs.end(), [&](const auto& config) {
+        if (config.portId == in_portId) {
+            // Check if the configuration was provided by the client.
+            const auto& initialIt = findById<AudioPortConfig>(initials, config.id);
+            return initialIt == initials.end() || config != *initialIt;
+        }
+        return false;
+    });
+    if (configIt != configs.end()) {
+        LOG(ERROR) << __func__ << ": port id " << in_portId << " has a non-default config with id "
+                   << configIt->id;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    ports.erase(portIt);
+    mConnectedDevicePorts.erase(in_portId);
+    LOG(DEBUG) << __func__ << ": connected device port " << in_portId << " released";
+
+    auto& routes = getConfig().routes;
+    for (auto routesIt = routes.begin(); routesIt != routes.end();) {
+        if (routesIt->sinkPortId == in_portId) {
+            routesIt = routes.erase(routesIt);
+        } else {
+            // Note: the list of sourcePortIds can't become empty because there must
+            // be the id of the template port in the route.
+            erase_if(routesIt->sourcePortIds, [in_portId](auto src) { return src == in_portId; });
+            ++routesIt;
+        }
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus Module::getAudioPatches(std::vector<AudioPatch>* _aidl_return) {
     *_aidl_return = getConfig().patches;
     LOG(DEBUG) << __func__ << ": returning " << _aidl_return->size() << " patches";
@@ -171,6 +319,23 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Module::getAudioRoutesForAudioPort(int32_t in_portId,
+                                                      std::vector<AudioRoute>* _aidl_return) {
+    auto& ports = getConfig().ports;
+    if (auto portIt = findById<AudioPort>(ports, in_portId); portIt == ports.end()) {
+        LOG(ERROR) << __func__ << ": port id " << in_portId << " not found";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    auto& routes = getConfig().routes;
+    std::copy_if(routes.begin(), routes.end(), std::back_inserter(*_aidl_return),
+                 [&](const auto& r) {
+                     const auto& srcs = r.sourcePortIds;
+                     return r.sinkPortId == in_portId ||
+                            std::find(srcs.begin(), srcs.end(), in_portId) != srcs.end();
+                 });
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus Module::openInputStream(int32_t in_portConfigId,
                                            const SinkMetadata& in_sinkMetadata,
                                            std::shared_ptr<IStreamIn>* _aidl_return) {
@@ -240,6 +405,14 @@
                    << " does not correspond to an output mix port";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
+    if (portConfigIt->flags.has_value() &&
+        ((portConfigIt->flags.value().get<AudioIoFlags::Tag::output>() &
+          1 << static_cast<int32_t>(AudioOutputFlags::COMPRESS_OFFLOAD)) != 0) &&
+        !in_offloadInfo.has_value()) {
+        LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
+                   << " has COMPRESS_OFFLOAD flag set, requires offload info";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
     if (mStreams.count(in_portConfigId) != 0) {
         LOG(ERROR) << __func__ << ": port config id " << in_portConfigId
                    << " already has a stream opened on it";
@@ -259,6 +432,7 @@
 }
 
 ndk::ScopedAStatus Module::setAudioPatch(const AudioPatch& in_requested, AudioPatch* _aidl_return) {
+    LOG(DEBUG) << __func__ << ": requested patch " << in_requested.toString();
     if (in_requested.sourcePortConfigIds.empty()) {
         LOG(ERROR) << __func__ << ": requested patch has empty sources list";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
diff --git a/audio/aidl/default/include/core-impl/Configuration.h b/audio/aidl/default/include/core-impl/Configuration.h
index 17e342d..d5cd30b 100644
--- a/audio/aidl/default/include/core-impl/Configuration.h
+++ b/audio/aidl/default/include/core-impl/Configuration.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <map>
 #include <vector>
 
 #include <aidl/android/hardware/audio/core/AudioPatch.h>
@@ -29,6 +30,9 @@
     std::vector<::aidl::android::media::audio::common::AudioPort> ports;
     std::vector<::aidl::android::media::audio::common::AudioPortConfig> portConfigs;
     std::vector<::aidl::android::media::audio::common::AudioPortConfig> initialConfigs;
+    // Port id -> List of profiles to use when the device port state is set to 'connected'.
+    std::map<int32_t, std::vector<::aidl::android::media::audio::common::AudioProfile>>
+            connectedProfiles;
     std::vector<AudioRoute> routes;
     std::vector<AudioPatch> patches;
     int32_t nextPortId = 1;
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 359626c..81a02ba 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -18,6 +18,7 @@
 
 #include <map>
 #include <memory>
+#include <set>
 
 #include <aidl/android/hardware/audio/core/BnModule.h>
 
@@ -27,6 +28,12 @@
 namespace aidl::android::hardware::audio::core {
 
 class Module : public BnModule {
+    ndk::ScopedAStatus setModuleDebug(
+            const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) override;
+    ndk::ScopedAStatus connectExternalDevice(
+            const ::aidl::android::media::audio::common::AudioPort& in_templateIdAndAdditionalData,
+            ::aidl::android::media::audio::common::AudioPort* _aidl_return) override;
+    ndk::ScopedAStatus disconnectExternalDevice(int32_t in_portId) override;
     ndk::ScopedAStatus getAudioPatches(std::vector<AudioPatch>* _aidl_return) override;
     ndk::ScopedAStatus getAudioPort(
             int32_t in_portId,
@@ -37,6 +44,9 @@
     ndk::ScopedAStatus getAudioPorts(
             std::vector<::aidl::android::media::audio::common::AudioPort>* _aidl_return) override;
     ndk::ScopedAStatus getAudioRoutes(std::vector<AudioRoute>* _aidl_return) override;
+    ndk::ScopedAStatus getAudioRoutesForAudioPort(
+            int32_t in_portId,
+            std::vector<::aidl::android::hardware::audio::core::AudioRoute>* _aidl_return) override;
     ndk::ScopedAStatus openInputStream(
             int32_t in_portConfigId,
             const ::aidl::android::hardware::audio::common::SinkMetadata& in_sinkMetadata,
@@ -63,6 +73,9 @@
     void registerPatch(const AudioPatch& patch);
 
     std::unique_ptr<internal::Configuration> mConfig;
+    ModuleDebug mDebug;
+    // ids of ports created at runtime via 'connectExternalDevice'.
+    std::set<int32_t> mConnectedDevicePorts;
     Streams mStreams;
     // Maps port ids and port config ids to patch ids.
     // Multimap because both ports and configs can be used by multiple patches.
diff --git a/audio/aidl/default/include/core-impl/utils.h b/audio/aidl/default/include/core-impl/utils.h
index 7101012..9d06f08 100644
--- a/audio/aidl/default/include/core-impl/utils.h
+++ b/audio/aidl/default/include/core-impl/utils.h
@@ -38,11 +38,11 @@
     return oldSize - c.size();
 }
 
-// Erase all the elements in the map that satisfy the provided predicate.
+// Erase all the elements in the container that satisfy the provided predicate.
 template <typename C, typename P>
 auto erase_if(C& c, P pred) {
     auto oldSize = c.size();
-    for (auto it = c.begin(), last = c.end(); it != last;) {
+    for (auto it = c.begin(); it != c.end();) {
         if (pred(*it)) {
             it = c.erase(it);
         } else {
diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp
index 0de6047..aeb9983 100644
--- a/audio/aidl/default/main.cpp
+++ b/audio/aidl/default/main.cpp
@@ -25,20 +25,22 @@
 using aidl::android::hardware::audio::core::Module;
 
 int main() {
+    // This is a debug implementation, always enable debug logging.
+    android::base::SetMinimumLogSeverity(::android::base::DEBUG);
     ABinderProcess_setThreadPoolMaxThreadCount(16);
 
-    // make the default config service
+    // Make the default config service
     auto config = ndk::SharedRefBase::make<Config>();
     const std::string configName = std::string() + Config::descriptor + "/default";
     binder_status_t status =
             AServiceManager_addService(config->asBinder().get(), configName.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(STATUS_OK, status);
 
-    // make the default module
+    // Make the default module
     auto moduleDefault = ndk::SharedRefBase::make<Module>();
     const std::string moduleDefaultName = std::string() + Module::descriptor + "/default";
     status = AServiceManager_addService(moduleDefault->asBinder().get(), moduleDefaultName.c_str());
-    CHECK(status == STATUS_OK);
+    CHECK_EQ(STATUS_OK, status);
 
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reach
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index c160d1f..cd5915b 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -18,12 +18,12 @@
         "VtsHalAudioCoreTargetTest.cpp",
     ],
     shared_libs: [
-        "libbinder",
+        "libbinder_ndk",
     ],
     static_libs: [
-        "android.hardware.audio.common-V1-cpp",
-        "android.hardware.audio.core-V1-cpp",
-        "android.media.audio.common.types-V1-cpp",
+        "android.hardware.audio.common-V1-ndk",
+        "android.hardware.audio.core-V1-ndk",
+        "android.media.audio.common.types-V1-ndk",
     ],
     test_suites: [
         "general-tests",
diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp
index 3faa39a..969b0e9 100644
--- a/audio/aidl/vts/ModuleConfig.cpp
+++ b/audio/aidl/vts/ModuleConfig.cpp
@@ -15,25 +15,50 @@
  */
 
 #include <algorithm>
+#include <chrono>
 
-#include <android/media/audio/common/AudioIoFlags.h>
-#include <android/media/audio/common/AudioOutputFlags.h>
+#include <aidl/android/media/audio/common/AudioIoFlags.h>
+#include <aidl/android/media/audio/common/AudioOutputFlags.h>
 
 #include "ModuleConfig.h"
 
 using namespace android;
+using namespace std::chrono_literals;
 
-using android::hardware::audio::core::IModule;
-using android::media::audio::common::AudioChannelLayout;
-using android::media::audio::common::AudioFormatDescription;
-using android::media::audio::common::AudioFormatType;
-using android::media::audio::common::AudioIoFlags;
-using android::media::audio::common::AudioOutputFlags;
-using android::media::audio::common::AudioPort;
-using android::media::audio::common::AudioPortConfig;
-using android::media::audio::common::AudioPortExt;
-using android::media::audio::common::AudioProfile;
-using android::media::audio::common::Int;
+using aidl::android::hardware::audio::core::IModule;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioEncapsulationMode;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::AudioOutputFlags;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioProfile;
+using aidl::android::media::audio::common::AudioUsage;
+using aidl::android::media::audio::common::Int;
+
+// static
+std::optional<AudioOffloadInfo> ModuleConfig::generateOffloadInfoIfNeeded(
+        const AudioPortConfig& portConfig) {
+    if (portConfig.flags.has_value() &&
+        portConfig.flags.value().getTag() == AudioIoFlags::Tag::output &&
+        (portConfig.flags.value().get<AudioIoFlags::Tag::output>() &
+         1 << static_cast<int>(AudioOutputFlags::COMPRESS_OFFLOAD)) != 0) {
+        AudioOffloadInfo offloadInfo;
+        offloadInfo.base.sampleRate = portConfig.sampleRate.value().value;
+        offloadInfo.base.channelMask = portConfig.channelMask.value();
+        offloadInfo.base.format = portConfig.format.value();
+        offloadInfo.bitRatePerSecond = 256;                                // Arbitrary value.
+        offloadInfo.durationUs = std::chrono::microseconds(1min).count();  // Arbitrary value.
+        offloadInfo.usage = AudioUsage::MEDIA;
+        offloadInfo.encapsulationMode = AudioEncapsulationMode::NONE;
+        return offloadInfo;
+    }
+    return {};
+}
 
 template <typename T>
 auto findById(const std::vector<T>& v, int32_t id) {
@@ -46,14 +71,16 @@
     for (const auto& port : mPorts) {
         if (port.ext.getTag() != AudioPortExt::Tag::device) continue;
         const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
-        const bool isInput = port.flags.getTag() == AudioIoFlags::Tag::input;
         if (devicePort.device.type.connection.empty()) {
+            const bool isInput = port.flags.getTag() == AudioIoFlags::Tag::input;
             // Permanently attached device.
             if (isInput) {
                 mAttachedSourceDevicePorts.insert(port.id);
             } else {
                 mAttachedSinkDevicePorts.insert(port.id);
             }
+        } else if (port.profiles.empty()) {
+            mExternalDevicePorts.insert(port.id);
         }
     }
     if (!mStatus.isOk()) return;
@@ -62,6 +89,22 @@
     mStatus = module->getAudioPortConfigs(&mInitialConfigs);
 }
 
+std::vector<AudioPort> ModuleConfig::getAttachedDevicePorts() const {
+    std::vector<AudioPort> result;
+    std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
+        return mAttachedSinkDevicePorts.count(port.id) != 0 ||
+               mAttachedSourceDevicePorts.count(port.id) != 0;
+    });
+    return result;
+}
+
+std::vector<AudioPort> ModuleConfig::getExternalDevicePorts() const {
+    std::vector<AudioPort> result;
+    std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result),
+                 [&](const auto& port) { return mExternalDevicePorts.count(port.id) != 0; });
+    return result;
+}
+
 std::vector<AudioPort> ModuleConfig::getInputMixPorts() const {
     std::vector<AudioPort> result;
     std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [](const auto& port) {
@@ -229,10 +272,27 @@
     return result;
 }
 
-static std::vector<AudioPortConfig> combineAudioConfigs(const AudioPort& port,
-                                                        const AudioProfile& profile) {
-    std::vector<AudioPortConfig> configs;
-    configs.reserve(profile.channelMasks.size() * profile.sampleRates.size());
+std::string ModuleConfig::toString() const {
+    std::string result;
+    result.append("Ports: ");
+    result.append(android::internal::ToString(mPorts));
+    result.append("\nInitial configs: ");
+    result.append(android::internal::ToString(mInitialConfigs));
+    result.append("\nAttached sink device ports: ");
+    result.append(android::internal::ToString(mAttachedSinkDevicePorts));
+    result.append("\nAttached source device ports: ");
+    result.append(android::internal::ToString(mAttachedSourceDevicePorts));
+    result.append("\nExternal device ports: ");
+    result.append(android::internal::ToString(mExternalDevicePorts));
+    result.append("\nRoutes: ");
+    result.append(android::internal::ToString(mRoutes));
+    return result;
+}
+
+static size_t combineAudioConfigs(const AudioPort& port, const AudioProfile& profile,
+                                  std::vector<AudioPortConfig>* result) {
+    const size_t newConfigCount = profile.channelMasks.size() * profile.sampleRates.size();
+    result->reserve(result->capacity() + newConfigCount);
     for (auto channelMask : profile.channelMasks) {
         for (auto sampleRate : profile.sampleRates) {
             AudioPortConfig config{};
@@ -242,66 +302,32 @@
             config.sampleRate = sr;
             config.channelMask = channelMask;
             config.format = profile.format;
+            config.flags = port.flags;
             config.ext = port.ext;
-            configs.push_back(config);
+            result->push_back(std::move(config));
         }
     }
-    return configs;
+    return newConfigCount;
 }
 
-std::vector<AudioPortConfig> ModuleConfig::generateInputAudioMixPortConfigs(
-        const std::vector<AudioPort>& ports, bool singleProfile) const {
+static bool isDynamicProfile(const AudioProfile& profile) {
+    return (profile.format.type == AudioFormatType::DEFAULT && profile.format.encoding.empty()) ||
+           profile.sampleRates.empty() || profile.channelMasks.empty();
+}
+
+std::vector<AudioPortConfig> ModuleConfig::generateAudioMixPortConfigs(
+        const std::vector<AudioPort>& ports, bool isInput, bool singleProfile) const {
     std::vector<AudioPortConfig> result;
     for (const auto& mixPort : ports) {
-        if (getAttachedSourceDevicesPortsForMixPort(mixPort).empty()) {
-            continue;  // no attached devices
+        if (getAttachedDevicesPortsForMixPort(isInput, mixPort).empty()) {
+            continue;
         }
         for (const auto& profile : mixPort.profiles) {
-            if (profile.format.type == AudioFormatType::DEFAULT || profile.sampleRates.empty() ||
-                profile.channelMasks.empty()) {
-                continue;  // dynamic profile
-            }
-            auto configs = combineAudioConfigs(mixPort, profile);
-            for (auto& config : configs) {
-                config.flags = mixPort.flags;
-                result.push_back(config);
-                if (singleProfile) return result;
-            }
-        }
-    }
-    return result;
-}
-
-static std::tuple<AudioIoFlags, bool> generateOutFlags(const AudioPort& mixPort) {
-    static const AudioIoFlags offloadFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(
-            (1 << static_cast<int>(AudioOutputFlags::COMPRESS_OFFLOAD)) |
-            (1 << static_cast<int>(AudioOutputFlags::DIRECT)));
-    const bool isOffload = (mixPort.flags.get<AudioIoFlags::Tag::output>() &
-                            (1 << static_cast<int>(AudioOutputFlags::COMPRESS_OFFLOAD))) != 0;
-    return {isOffload ? offloadFlags : mixPort.flags, isOffload};
-}
-
-std::vector<AudioPortConfig> ModuleConfig::generateOutputAudioMixPortConfigs(
-        const std::vector<AudioPort>& ports, bool singleProfile) const {
-    std::vector<AudioPortConfig> result;
-    for (const auto& mixPort : ports) {
-        if (getAttachedSinkDevicesPortsForMixPort(mixPort).empty()) {
-            continue;  // no attached devices
-        }
-        auto [flags, isOffload] = generateOutFlags(mixPort);
-        (void)isOffload;
-        for (const auto& profile : mixPort.profiles) {
-            if (profile.format.type == AudioFormatType::DEFAULT) continue;
-            auto configs = combineAudioConfigs(mixPort, profile);
-            for (auto& config : configs) {
-                // Some combinations of flags declared in the config file require special
-                // treatment.
-                // if (isOffload) {
-                //     config.offloadInfo.info(generateOffloadInfo(config.base));
-                // }
-                config.flags = flags;
-                result.push_back(config);
-                if (singleProfile) return result;
+            if (isDynamicProfile(profile)) continue;
+            combineAudioConfigs(mixPort, profile, &result);
+            if (singleProfile && !result.empty()) {
+                result.resize(1);
+                return result;
             }
         }
     }
@@ -314,15 +340,21 @@
     for (const auto& devicePort : ports) {
         const size_t resultSizeBefore = result.size();
         for (const auto& profile : devicePort.profiles) {
-            auto configs = combineAudioConfigs(devicePort, profile);
-            result.insert(result.end(), configs.begin(), configs.end());
-            if (singleProfile && !result.empty()) return result;
+            combineAudioConfigs(devicePort, profile, &result);
+            if (singleProfile && !result.empty()) {
+                result.resize(1);
+                return result;
+            }
         }
         if (resultSizeBefore == result.size()) {
-            AudioPortConfig empty;
-            empty.portId = devicePort.id;
-            empty.ext = devicePort.ext;
-            result.push_back(empty);
+            std::copy_if(mInitialConfigs.begin(), mInitialConfigs.end(), std::back_inserter(result),
+                         [&](const auto& config) { return config.portId == devicePort.id; });
+            if (resultSizeBefore == result.size()) {
+                AudioPortConfig empty;
+                empty.portId = devicePort.id;
+                empty.ext = devicePort.ext;
+                result.push_back(empty);
+            }
         }
         if (singleProfile) return result;
     }
diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h
index 2e86b97..df13430 100644
--- a/audio/aidl/vts/ModuleConfig.h
+++ b/audio/aidl/vts/ModuleConfig.h
@@ -21,111 +21,119 @@
 #include <utility>
 #include <vector>
 
-#include <android/hardware/audio/core/AudioRoute.h>
-#include <android/hardware/audio/core/IModule.h>
-#include <android/media/audio/common/AudioPort.h>
-#include <binder/Status.h>
+#include <aidl/android/hardware/audio/core/AudioRoute.h>
+#include <aidl/android/hardware/audio/core/IModule.h>
+#include <aidl/android/media/audio/common/AudioOffloadInfo.h>
+#include <aidl/android/media/audio/common/AudioPort.h>
 
 class ModuleConfig {
   public:
-    using SrcSinkPair = std::pair<android::media::audio::common::AudioPortConfig,
-                                  android::media::audio::common::AudioPortConfig>;
+    using SrcSinkPair = std::pair<aidl::android::media::audio::common::AudioPortConfig,
+                                  aidl::android::media::audio::common::AudioPortConfig>;
     using SrcSinkGroup =
-            std::pair<android::hardware::audio::core::AudioRoute, std::vector<SrcSinkPair>>;
+            std::pair<aidl::android::hardware::audio::core::AudioRoute, std::vector<SrcSinkPair>>;
 
-    explicit ModuleConfig(android::hardware::audio::core::IModule* module);
-    android::binder::Status getStatus() const { return mStatus; }
-    std::string getError() const { return mStatus.toString8().c_str(); }
+    static std::optional<aidl::android::media::audio::common::AudioOffloadInfo>
+    generateOffloadInfoIfNeeded(
+            const aidl::android::media::audio::common::AudioPortConfig& portConfig);
 
-    std::vector<android::media::audio::common::AudioPort> getInputMixPorts() const;
-    std::vector<android::media::audio::common::AudioPort> getOutputMixPorts() const;
-    std::vector<android::media::audio::common::AudioPort> getMixPorts(bool isInput) const {
+    explicit ModuleConfig(aidl::android::hardware::audio::core::IModule* module);
+    const ndk::ScopedAStatus& getStatus() const { return mStatus; }
+    std::string getError() const { return mStatus.getMessage(); }
+
+    std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicePorts() const;
+    std::vector<aidl::android::media::audio::common::AudioPort> getExternalDevicePorts() const;
+    std::vector<aidl::android::media::audio::common::AudioPort> getInputMixPorts() const;
+    std::vector<aidl::android::media::audio::common::AudioPort> getOutputMixPorts() const;
+    std::vector<aidl::android::media::audio::common::AudioPort> getMixPorts(bool isInput) const {
         return isInput ? getInputMixPorts() : getOutputMixPorts();
     }
 
-    std::vector<android::media::audio::common::AudioPort> getAttachedDevicesPortsForMixPort(
-            bool isInput, const android::media::audio::common::AudioPort& mixPort) const {
+    std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicesPortsForMixPort(
+            bool isInput, const aidl::android::media::audio::common::AudioPort& mixPort) const {
         return isInput ? getAttachedSourceDevicesPortsForMixPort(mixPort)
                        : getAttachedSinkDevicesPortsForMixPort(mixPort);
     }
-    std::vector<android::media::audio::common::AudioPort> getAttachedSinkDevicesPortsForMixPort(
-            const android::media::audio::common::AudioPort& mixPort) const;
-    std::vector<android::media::audio::common::AudioPort> getAttachedSourceDevicesPortsForMixPort(
-            const android::media::audio::common::AudioPort& mixPort) const;
-    std::optional<android::media::audio::common::AudioPort> getSourceMixPortForAttachedDevice()
-            const;
+    std::vector<aidl::android::media::audio::common::AudioPort>
+    getAttachedSinkDevicesPortsForMixPort(
+            const aidl::android::media::audio::common::AudioPort& mixPort) const;
+    std::vector<aidl::android::media::audio::common::AudioPort>
+    getAttachedSourceDevicesPortsForMixPort(
+            const aidl::android::media::audio::common::AudioPort& mixPort) const;
+    std::optional<aidl::android::media::audio::common::AudioPort>
+    getSourceMixPortForAttachedDevice() const;
 
     std::optional<SrcSinkPair> getNonRoutableSrcSinkPair(bool isInput) const;
     std::optional<SrcSinkPair> getRoutableSrcSinkPair(bool isInput) const;
     std::vector<SrcSinkGroup> getRoutableSrcSinkGroups(bool isInput) const;
 
-    std::vector<android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts() const {
-        auto inputs = generateInputAudioMixPortConfigs(getInputMixPorts(), false);
-        auto outputs = generateOutputAudioMixPortConfigs(getOutputMixPorts(), false);
+    std::vector<aidl::android::media::audio::common::AudioPortConfig>
+    getPortConfigsForAttachedDevicePorts() const {
+        return generateAudioDevicePortConfigs(getAttachedDevicePorts(), false);
+    }
+    std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts()
+            const {
+        auto inputs = generateAudioMixPortConfigs(getInputMixPorts(), true, false);
+        auto outputs = generateAudioMixPortConfigs(getOutputMixPorts(), false, false);
         inputs.insert(inputs.end(), outputs.begin(), outputs.end());
         return inputs;
     }
-    std::vector<android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
+    std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
             bool isInput) const {
-        return isInput ? generateInputAudioMixPortConfigs(getInputMixPorts(), false)
-                       : generateOutputAudioMixPortConfigs(getOutputMixPorts(), false);
+        return generateAudioMixPortConfigs(getMixPorts(isInput), isInput, false);
     }
-    std::vector<android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
-            bool isInput, const android::media::audio::common::AudioPort& port) const {
-        return isInput ? generateInputAudioMixPortConfigs({port}, false)
-                       : generateOutputAudioMixPortConfigs({port}, false);
+    std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
+            bool isInput, const aidl::android::media::audio::common::AudioPort& port) const {
+        return generateAudioMixPortConfigs({port}, isInput, false);
     }
-    std::optional<android::media::audio::common::AudioPortConfig> getSingleConfigForMixPort(
+    std::optional<aidl::android::media::audio::common::AudioPortConfig> getSingleConfigForMixPort(
             bool isInput) const {
-        const auto config = isInput ? generateInputAudioMixPortConfigs(getInputMixPorts(), true)
-                                    : generateOutputAudioMixPortConfigs(getOutputMixPorts(), true);
-        // TODO: Avoid returning configs for offload since they require an extra
-        //       argument to openOutputStream.
+        const auto config = generateAudioMixPortConfigs(getMixPorts(isInput), isInput, true);
         if (!config.empty()) {
             return *config.begin();
-        } else {
-            return {};
         }
+        return {};
     }
-    std::optional<android::media::audio::common::AudioPortConfig> getSingleConfigForMixPort(
-            bool isInput, const android::media::audio::common::AudioPort& port) const {
-        const auto config = isInput ? generateInputAudioMixPortConfigs({port}, true)
-                                    : generateOutputAudioMixPortConfigs({port}, true);
+    std::optional<aidl::android::media::audio::common::AudioPortConfig> getSingleConfigForMixPort(
+            bool isInput, const aidl::android::media::audio::common::AudioPort& port) const {
+        const auto config = generateAudioMixPortConfigs({port}, isInput, true);
         if (!config.empty()) {
             return *config.begin();
-        } else {
-            return {};
         }
+        return {};
     }
 
-    android::media::audio::common::AudioPortConfig getSingleConfigForDevicePort(
-            const android::media::audio::common::AudioPort& port) const {
-        for (const auto& config : mInitialConfigs) {
-            if (config.portId == port.id) return config;
-        }
+    std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForDevicePort(
+            const aidl::android::media::audio::common::AudioPort& port) const {
+        return generateAudioDevicePortConfigs({port}, false);
+    }
+    aidl::android::media::audio::common::AudioPortConfig getSingleConfigForDevicePort(
+            const aidl::android::media::audio::common::AudioPort& port) const {
         const auto config = generateAudioDevicePortConfigs({port}, true);
         return *config.begin();
     }
 
+    std::string toString() const;
+
   private:
-    std::vector<android::media::audio::common::AudioPortConfig> generateInputAudioMixPortConfigs(
-            const std::vector<android::media::audio::common::AudioPort>& ports,
-            bool singleProfile) const;
-    std::vector<android::media::audio::common::AudioPortConfig> generateOutputAudioMixPortConfigs(
-            const std::vector<android::media::audio::common::AudioPort>& ports,
+    std::vector<aidl::android::media::audio::common::AudioPortConfig> generateAudioMixPortConfigs(
+            const std::vector<aidl::android::media::audio::common::AudioPort>& ports, bool isInput,
             bool singleProfile) const;
 
     // Unlike MixPorts, the generator for DevicePorts always returns a non-empty
     // vector for a non-empty input port list. If there are no profiles in the
-    // port, a vector with an empty config is returned.
-    std::vector<android::media::audio::common::AudioPortConfig> generateAudioDevicePortConfigs(
-            const std::vector<android::media::audio::common::AudioPort>& ports,
+    // port, its initial configs are looked up, if there are none,
+    // then an empty config is used, assuming further negotiation via setAudioPortConfig.
+    std::vector<aidl::android::media::audio::common::AudioPortConfig>
+    generateAudioDevicePortConfigs(
+            const std::vector<aidl::android::media::audio::common::AudioPort>& ports,
             bool singleProfile) const;
 
-    android::binder::Status mStatus = android::binder::Status::ok();
-    std::vector<android::media::audio::common::AudioPort> mPorts;
-    std::vector<android::media::audio::common::AudioPortConfig> mInitialConfigs;
+    ndk::ScopedAStatus mStatus = ndk::ScopedAStatus::ok();
+    std::vector<aidl::android::media::audio::common::AudioPort> mPorts;
+    std::vector<aidl::android::media::audio::common::AudioPortConfig> mInitialConfigs;
     std::set<int32_t> mAttachedSinkDevicePorts;
     std::set<int32_t> mAttachedSourceDevicePorts;
-    std::vector<android::hardware::audio::core::AudioRoute> mRoutes;
+    std::set<int32_t> mExternalDevicePorts;
+    std::vector<aidl::android::hardware::audio::core::AudioRoute> mRoutes;
 };
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
index cadeb0c..bb24365 100644
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
@@ -22,40 +22,53 @@
 #include <set>
 #include <string>
 
+#define LOG_TAG "VtsHalAudioCore"
+#include <android-base/logging.h>
+
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
+#include <aidl/android/hardware/audio/core/IConfig.h>
+#include <aidl/android/hardware/audio/core/IModule.h>
+#include <aidl/android/media/audio/common/AudioIoFlags.h>
+#include <aidl/android/media/audio/common/AudioOutputFlags.h>
 #include <android-base/properties.h>
-#include <android/hardware/audio/core/IConfig.h>
-#include <android/hardware/audio/core/IModule.h>
-#include <android/media/audio/common/AudioIoFlags.h>
-#include <android/media/audio/common/AudioOutputFlags.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
 
 #include "ModuleConfig.h"
 
 using namespace android;
-using android::binder::Status;
-using android::hardware::audio::common::PlaybackTrackMetadata;
-using android::hardware::audio::common::RecordTrackMetadata;
-using android::hardware::audio::common::SinkMetadata;
-using android::hardware::audio::common::SourceMetadata;
-using android::hardware::audio::core::AudioPatch;
-using android::hardware::audio::core::AudioRoute;
-using android::hardware::audio::core::IModule;
-using android::hardware::audio::core::IStreamIn;
-using android::hardware::audio::core::IStreamOut;
-using android::media::audio::common::AudioContentType;
-using android::media::audio::common::AudioDevice;
-using android::media::audio::common::AudioDeviceType;
-using android::media::audio::common::AudioIoFlags;
-using android::media::audio::common::AudioOutputFlags;
-using android::media::audio::common::AudioPort;
-using android::media::audio::common::AudioPortConfig;
-using android::media::audio::common::AudioPortDeviceExt;
-using android::media::audio::common::AudioPortExt;
-using android::media::audio::common::AudioSource;
-using android::media::audio::common::AudioUsage;
+using aidl::android::hardware::audio::common::PlaybackTrackMetadata;
+using aidl::android::hardware::audio::common::RecordTrackMetadata;
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::audio::core::AudioPatch;
+using aidl::android::hardware::audio::core::AudioRoute;
+using aidl::android::hardware::audio::core::IModule;
+using aidl::android::hardware::audio::core::IStreamIn;
+using aidl::android::hardware::audio::core::IStreamOut;
+using aidl::android::hardware::audio::core::ModuleDebug;
+using aidl::android::media::audio::common::AudioContentType;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioOutputFlags;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortDeviceExt;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::AudioUsage;
+using ndk::ScopedAStatus;
+
+namespace ndk {
+std::ostream& operator<<(std::ostream& str, const ScopedAStatus& status) {
+    str << status.getDescription();
+    return str;
+}
+}  // namespace ndk
 
 template <typename T>
 auto findById(std::vector<T>& v, int32_t id) {
@@ -63,7 +76,7 @@
 }
 
 template <typename C>
-std::vector<int32_t> getNonExistentIds(const C& allIds) {
+std::vector<int32_t> GetNonExistentIds(const C& allIds) {
     if (allIds.empty()) {
         return std::vector<int32_t>{-1, 0, 1};
     }
@@ -73,16 +86,29 @@
     return nonExistentIds;
 }
 
-struct AidlDeathRecipient : IBinder::DeathRecipient {
+AudioDeviceAddress GenerateUniqueDeviceAddress() {
+    static int nextId = 1;
+    // TODO: Use connection-specific ID.
+    return AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(std::to_string(++nextId));
+}
+
+struct AidlDeathRecipient {
+    const ndk::SpAIBinder binder;
+    const ndk::ScopedAIBinder_DeathRecipient recipient;
     std::mutex mutex;
     std::condition_variable condition;
     bool fired = false;
-    wp<IBinder> who;
 
-    void binderDied(const wp<IBinder>& who) override {
+    explicit AidlDeathRecipient(const ndk::SpAIBinder& binder)
+        : binder(binder), recipient(AIBinder_DeathRecipient_new(&binderDiedCallbackAidl)) {}
+
+    binder_status_t linkToDeath() {
+        return AIBinder_linkToDeath(binder.get(), recipient.get(), this);
+    }
+
+    void binderDied() {
         std::unique_lock<std::mutex> lock(mutex);
         fired = true;
-        this->who = who;
         condition.notify_one();
     };
 
@@ -91,6 +117,11 @@
         condition.wait_for(lock, std::chrono::milliseconds(timeoutMs), [this]() { return fired; });
         return fired;
     }
+
+    static void binderDiedCallbackAidl(void* cookie) {
+        AidlDeathRecipient* self = static_cast<AidlDeathRecipient*>(cookie);
+        self->binderDied();
+    }
 };
 
 template <typename T>
@@ -107,34 +138,158 @@
     return false;
 }
 
+// All 'With*' classes are move-only because they are associated with some
+// resource or state of a HAL module.
+class WithDebugFlags {
+  public:
+    static WithDebugFlags createNested(const WithDebugFlags& parent) {
+        return WithDebugFlags(parent.mFlags);
+    }
+
+    WithDebugFlags() {}
+    explicit WithDebugFlags(const ModuleDebug& initial) : mInitial(initial), mFlags(initial) {}
+    WithDebugFlags(const WithDebugFlags&) = delete;
+    WithDebugFlags& operator=(const WithDebugFlags&) = delete;
+    ~WithDebugFlags() {
+        if (mModule != nullptr) {
+            ScopedAStatus status = mModule->setModuleDebug(mInitial);
+            EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status;
+        }
+    }
+    void SetUp(IModule* module) {
+        ScopedAStatus status = module->setModuleDebug(mFlags);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
+    }
+    ModuleDebug& flags() { return mFlags; }
+
+  private:
+    ModuleDebug mInitial;
+    ModuleDebug mFlags;
+    IModule* mModule = nullptr;
+};
+
+// For consistency, WithAudioPortConfig can start both with a non-existent
+// port config, and with an existing one. Existence is determined by the
+// id of the provided config. If it's not 0, then WithAudioPortConfig is
+// essentially a no-op wrapper.
+class WithAudioPortConfig {
+  public:
+    WithAudioPortConfig() {}
+    explicit WithAudioPortConfig(const AudioPortConfig& config) : mInitialConfig(config) {}
+    WithAudioPortConfig(const WithAudioPortConfig&) = delete;
+    WithAudioPortConfig& operator=(const WithAudioPortConfig&) = delete;
+    ~WithAudioPortConfig() {
+        if (mModule != nullptr) {
+            ScopedAStatus status = mModule->resetAudioPortConfig(getId());
+            EXPECT_EQ(EX_NONE, status.getExceptionCode())
+                    << status << "; port config id " << getId();
+        }
+    }
+    void SetUp(IModule* module) {
+        ASSERT_NE(AudioPortExt::Tag::unspecified, mInitialConfig.ext.getTag())
+                << "config: " << mInitialConfig.toString();
+        // Negotiation is allowed for device ports because the HAL module is
+        // allowed to provide an empty profiles list for attached devices.
+        ASSERT_NO_FATAL_FAILURE(
+                SetUpImpl(module, mInitialConfig.ext.getTag() == AudioPortExt::Tag::device));
+    }
+    int32_t getId() const { return mConfig.id; }
+    const AudioPortConfig& get() const { return mConfig; }
+
+  private:
+    void SetUpImpl(IModule* module, bool negotiate) {
+        if (mInitialConfig.id == 0) {
+            AudioPortConfig suggested;
+            bool applied = false;
+            ScopedAStatus status = module->setAudioPortConfig(mInitialConfig, &suggested, &applied);
+            ASSERT_EQ(EX_NONE, status.getExceptionCode())
+                    << status << "; Config: " << mInitialConfig.toString();
+            if (!applied && negotiate) {
+                mInitialConfig = suggested;
+                ASSERT_NO_FATAL_FAILURE(SetUpImpl(module, false))
+                        << " while applying suggested config: " << suggested.toString();
+            } else {
+                ASSERT_TRUE(applied) << "Suggested: " << suggested.toString();
+                mConfig = suggested;
+                mModule = module;
+            }
+        } else {
+            mConfig = mInitialConfig;
+        }
+    }
+
+    AudioPortConfig mInitialConfig;
+    IModule* mModule = nullptr;
+    AudioPortConfig mConfig;
+};
+
 class AudioCoreModule : public testing::TestWithParam<std::string> {
   public:
-    void SetUp() override { ASSERT_NO_FATAL_FAILURE(ConnectToService()); }
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(ConnectToService());
+        debug.flags().simulateDeviceConnections = true;
+        ASSERT_NO_FATAL_FAILURE(debug.SetUp(module.get()));
+    }
+
+    void TearDown() override {
+        if (module != nullptr) {
+            ScopedAStatus status = module->setModuleDebug(ModuleDebug{});
+            EXPECT_EQ(EX_NONE, status.getExceptionCode())
+                    << status << " returned when resetting debug flags";
+        }
+    }
 
     void ConnectToService() {
-        module = android::waitForDeclaredService<IModule>(String16(GetParam().c_str()));
+        module = IModule::fromBinder(
+                ndk::SpAIBinder(AServiceManager_getService(GetParam().c_str())));
         ASSERT_NE(module, nullptr);
     }
 
     void RestartService() {
         ASSERT_NE(module, nullptr);
         moduleConfig.reset();
-        deathHandler = sp<AidlDeathRecipient>::make();
-        ASSERT_EQ(NO_ERROR, IModule::asBinder(module)->linkToDeath(deathHandler));
+        deathHandler.reset(new AidlDeathRecipient(module->asBinder()));
+        ASSERT_EQ(STATUS_OK, deathHandler->linkToDeath());
         ASSERT_TRUE(base::SetProperty("sys.audio.restart.hal", "1"));
         EXPECT_TRUE(deathHandler->waitForFired(3000));
-        deathHandler = nullptr;
+        deathHandler.reset();
         ASSERT_NO_FATAL_FAILURE(ConnectToService());
     }
 
+    void ApplyEveryConfig(const std::vector<AudioPortConfig>& configs) {
+        for (const auto& config : configs) {
+            ASSERT_NE(0, config.portId);
+            WithAudioPortConfig portConfig(config);
+            ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));  // calls setAudioPortConfig
+            EXPECT_EQ(config.portId, portConfig.get().portId);
+            std::vector<AudioPortConfig> retrievedPortConfigs;
+            ScopedAStatus status = module->getAudioPortConfigs(&retrievedPortConfigs);
+            ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
+            const int32_t portConfigId = portConfig.getId();
+            auto configIt = std::find_if(
+                    retrievedPortConfigs.begin(), retrievedPortConfigs.end(),
+                    [&portConfigId](const auto& retrConf) { return retrConf.id == portConfigId; });
+            EXPECT_NE(configIt, retrievedPortConfigs.end())
+                    << "Port config id returned by setAudioPortConfig: " << portConfigId
+                    << " is not found in the list returned by getAudioPortConfigs";
+            if (configIt != retrievedPortConfigs.end()) {
+                EXPECT_EQ(portConfig.get(), *configIt)
+                        << "Applied port config returned by setAudioPortConfig: "
+                        << portConfig.get().toString()
+                        << " is not the same as retrieved via getAudioPortConfigs: "
+                        << configIt->toString();
+            }
+        }
+    }
+
     template <typename Entity>
     void GetAllEntityIds(std::set<int32_t>* entityIds,
-                         Status (IModule::*getter)(std::vector<Entity>*),
+                         ScopedAStatus (IModule::*getter)(std::vector<Entity>*),
                          const std::string& errorMessage) {
         std::vector<Entity> entities;
         {
-            Status status = (module.get()->*getter)(&entities);
-            ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+            ScopedAStatus status = (module.get()->*getter)(&entities);
+            ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
         }
         std::transform(entities.begin(), entities.end(),
                        std::inserter(*entityIds, entityIds->begin()),
@@ -163,67 +318,53 @@
     void SetUpModuleConfig() {
         if (moduleConfig == nullptr) {
             moduleConfig = std::make_unique<ModuleConfig>(module.get());
-            ASSERT_EQ(Status::EX_NONE, moduleConfig->getStatus().exceptionCode())
+            ASSERT_EQ(EX_NONE, moduleConfig->getStatus().getExceptionCode())
                     << "ModuleConfig init error: " << moduleConfig->getError();
         }
     }
 
-    sp<IModule> module;
-    sp<AidlDeathRecipient> deathHandler;
+    std::shared_ptr<IModule> module;
+    std::unique_ptr<AidlDeathRecipient> deathHandler;
     std::unique_ptr<ModuleConfig> moduleConfig;
+    WithDebugFlags debug;
 };
 
-// For consistency, WithAudioPortConfig can start both with a non-existent
-// port config, and with an existing one. Existence is determined by the
-// id of the provided config. If it's not 0, then WithAudioPortConfig is
-// essentially a no-op wrapper.
-class WithAudioPortConfig {
+class WithDevicePortConnectedState {
   public:
-    WithAudioPortConfig() {}
-    explicit WithAudioPortConfig(const AudioPortConfig& config) : mInitialConfig(config) {}
-    ~WithAudioPortConfig() {
+    explicit WithDevicePortConnectedState(const AudioPort& idAndData) : mIdAndData(idAndData) {}
+    WithDevicePortConnectedState(const AudioPort& id, const AudioDeviceAddress& address)
+        : mIdAndData(setAudioPortAddress(id, address)) {}
+    WithDevicePortConnectedState(const WithDevicePortConnectedState&) = delete;
+    WithDevicePortConnectedState& operator=(const WithDevicePortConnectedState&) = delete;
+    ~WithDevicePortConnectedState() {
         if (mModule != nullptr) {
-            Status status = mModule->resetAudioPortConfig(getId());
-            EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
-                    << status << "; port config id " << getId();
+            ScopedAStatus status = mModule->disconnectExternalDevice(getId());
+            EXPECT_EQ(EX_NONE, status.getExceptionCode())
+                    << status << " returned when disconnecting device port ID " << getId();
         }
     }
     void SetUp(IModule* module) {
-        ASSERT_NE(AudioPortExt::Tag::unspecified, mInitialConfig.ext.getTag())
-                << "config: " << mInitialConfig.toString();
-        // Negotiation is allowed for device ports because the HAL module is
-        // allowed to provide an empty profiles list for attached devices.
-        ASSERT_NO_FATAL_FAILURE(
-                SetUpImpl(module, mInitialConfig.ext.getTag() == AudioPortExt::Tag::device));
+        ScopedAStatus status = module->connectExternalDevice(mIdAndData, &mConnectedPort);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode())
+                << status << " returned when connecting device port ID & data "
+                << mIdAndData.toString();
+        ASSERT_NE(mIdAndData.id, getId())
+                << "ID of the connected port must not be the same as the ID of the template port";
+        mModule = module;
     }
-    int32_t getId() const { return mConfig.id; }
-    const AudioPortConfig& get() const { return mConfig; }
+    int32_t getId() const { return mConnectedPort.id; }
+    const AudioPort& get() { return mConnectedPort; }
 
   private:
-    void SetUpImpl(IModule* module, bool negotiate) {
-        if (mInitialConfig.id == 0) {
-            AudioPortConfig suggested;
-            bool applied = false;
-            Status status = module->setAudioPortConfig(mInitialConfig, &suggested, &applied);
-            ASSERT_EQ(Status::EX_NONE, status.exceptionCode())
-                    << status << "; Config: " << mInitialConfig.toString();
-            if (!applied && negotiate) {
-                mInitialConfig = suggested;
-                ASSERT_NO_FATAL_FAILURE(SetUpImpl(module, false))
-                        << " while applying suggested config: " << suggested.toString();
-            } else {
-                ASSERT_TRUE(applied) << "Suggested: " << suggested.toString();
-                mConfig = suggested;
-                mModule = module;
-            }
-        } else {
-            mConfig = mInitialConfig;
-        }
+    static AudioPort setAudioPortAddress(const AudioPort& id, const AudioDeviceAddress& address) {
+        AudioPort result = id;
+        result.ext.get<AudioPortExt::Tag::device>().device.address = address;
+        return result;
     }
 
-    AudioPortConfig mInitialConfig;
+    const AudioPort mIdAndData;
     IModule* mModule = nullptr;
-    AudioPortConfig mConfig;
+    AudioPort mConnectedPort;
 };
 
 template <typename Stream>
@@ -231,45 +372,54 @@
   public:
     WithStream() {}
     explicit WithStream(const AudioPortConfig& portConfig) : mPortConfig(portConfig) {}
+    WithStream(const WithStream&) = delete;
+    WithStream& operator=(const WithStream&) = delete;
     ~WithStream() {
         if (mStream != nullptr) {
-            Status status = mStream->close();
-            EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
+            ScopedAStatus status = mStream->close();
+            EXPECT_EQ(EX_NONE, status.getExceptionCode())
                     << status << "; port config id " << getPortId();
         }
     }
     void SetUpPortConfig(IModule* module) { ASSERT_NO_FATAL_FAILURE(mPortConfig.SetUp(module)); }
-    Status SetUpNoChecks(IModule* module) { return SetUpNoChecks(module, mPortConfig.get()); }
-    Status SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig);
+    ScopedAStatus SetUpNoChecks(IModule* module) {
+        return SetUpNoChecks(module, mPortConfig.get());
+    }
+    ScopedAStatus SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig);
     void SetUp(IModule* module) {
         ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module));
-        Status status = SetUpNoChecks(module);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode())
+        ScopedAStatus status = SetUpNoChecks(module);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode())
                 << status << "; port config id " << getPortId();
         ASSERT_NE(nullptr, mStream) << "; port config id " << getPortId();
     }
     Stream* get() const { return mStream.get(); }
+    std::shared_ptr<Stream> getSharedPointer() const { return mStream; }
     const AudioPortConfig& getPortConfig() const { return mPortConfig.get(); }
     int32_t getPortId() const { return mPortConfig.getId(); }
 
   private:
     WithAudioPortConfig mPortConfig;
-    sp<Stream> mStream;
+    std::shared_ptr<Stream> mStream;
 };
 
-template <>
-Status WithStream<IStreamIn>::SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig) {
+SinkMetadata GenerateSinkMetadata(const AudioPortConfig& portConfig) {
     RecordTrackMetadata trackMeta;
     trackMeta.source = AudioSource::MIC;
     trackMeta.gain = 1.0;
     trackMeta.channelMask = portConfig.channelMask.value();
     SinkMetadata metadata;
     metadata.tracks.push_back(trackMeta);
-    return module->openInputStream(portConfig.id, metadata, &mStream);
+    return metadata;
 }
 
 template <>
-Status WithStream<IStreamOut>::SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig) {
+ScopedAStatus WithStream<IStreamIn>::SetUpNoChecks(IModule* module,
+                                                   const AudioPortConfig& portConfig) {
+    return module->openInputStream(portConfig.id, GenerateSinkMetadata(portConfig), &mStream);
+}
+
+SourceMetadata GenerateSourceMetadata(const AudioPortConfig& portConfig) {
     PlaybackTrackMetadata trackMeta;
     trackMeta.usage = AudioUsage::MEDIA;
     trackMeta.contentType = AudioContentType::MUSIC;
@@ -277,7 +427,15 @@
     trackMeta.channelMask = portConfig.channelMask.value();
     SourceMetadata metadata;
     metadata.tracks.push_back(trackMeta);
-    return module->openOutputStream(portConfig.id, metadata, {}, &mStream);
+    return metadata;
+}
+
+template <>
+ScopedAStatus WithStream<IStreamOut>::SetUpNoChecks(IModule* module,
+                                                    const AudioPortConfig& portConfig) {
+    return module->openOutputStream(portConfig.id, GenerateSourceMetadata(portConfig),
+                                    ModuleConfig::generateOffloadInfoIfNeeded(portConfig),
+                                    &mStream);
 }
 
 class WithAudioPatch {
@@ -285,18 +443,19 @@
     WithAudioPatch() {}
     WithAudioPatch(const AudioPortConfig& srcPortConfig, const AudioPortConfig& sinkPortConfig)
         : mSrcPortConfig(srcPortConfig), mSinkPortConfig(sinkPortConfig) {}
+    WithAudioPatch(const WithAudioPatch&) = delete;
+    WithAudioPatch& operator=(const WithAudioPatch&) = delete;
     ~WithAudioPatch() {
         if (mModule != nullptr && mPatch.id != 0) {
-            Status status = mModule->resetAudioPatch(mPatch.id);
-            EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
-                    << status << "; patch id " << getId();
+            ScopedAStatus status = mModule->resetAudioPatch(mPatch.id);
+            EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status << "; patch id " << getId();
         }
     }
     void SetUpPortConfigs(IModule* module) {
         ASSERT_NO_FATAL_FAILURE(mSrcPortConfig.SetUp(module));
         ASSERT_NO_FATAL_FAILURE(mSinkPortConfig.SetUp(module));
     }
-    Status SetUpNoChecks(IModule* module) {
+    ScopedAStatus SetUpNoChecks(IModule* module) {
         mModule = module;
         mPatch.sourcePortConfigIds = std::vector<int32_t>{mSrcPortConfig.getId()};
         mPatch.sinkPortConfigIds = std::vector<int32_t>{mSinkPortConfig.getId()};
@@ -304,8 +463,8 @@
     }
     void SetUp(IModule* module) {
         ASSERT_NO_FATAL_FAILURE(SetUpPortConfigs(module));
-        Status status = SetUpNoChecks(module);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode())
+        ScopedAStatus status = SetUpNoChecks(module);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode())
                 << status << "; source port config id " << mSrcPortConfig.getId()
                 << "; sink port config id " << mSinkPortConfig.getId();
     }
@@ -332,37 +491,37 @@
     ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
 }
 
-TEST_P(AudioCoreModule, GetAudioPortsIsStatic) {
+TEST_P(AudioCoreModule, GetAudioPortsIsStable) {
     std::vector<AudioPort> ports1;
     {
-        Status status = module->getAudioPorts(&ports1);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioPorts(&ports1);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     std::vector<AudioPort> ports2;
     {
-        Status status = module->getAudioPorts(&ports2);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioPorts(&ports2);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     ASSERT_EQ(ports1.size(), ports2.size())
-            << "Sizes of audio port arrays do not match across calls to getAudioPorts";
+            << "Sizes of audio port arrays do not match across consequent calls to getAudioPorts";
     std::sort(ports1.begin(), ports1.end());
     std::sort(ports2.begin(), ports2.end());
     EXPECT_EQ(ports1, ports2);
 }
 
-TEST_P(AudioCoreModule, GetAudioRoutesIsStatic) {
+TEST_P(AudioCoreModule, GetAudioRoutesIsStable) {
     std::vector<AudioRoute> routes1;
     {
-        Status status = module->getAudioRoutes(&routes1);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioRoutes(&routes1);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     std::vector<AudioRoute> routes2;
     {
-        Status status = module->getAudioRoutes(&routes2);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioRoutes(&routes2);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     ASSERT_EQ(routes1.size(), routes2.size())
-            << "Sizes of audio route arrays do not match across calls to getAudioRoutes";
+            << "Sizes of audio route arrays do not match across consequent calls to getAudioRoutes";
     std::sort(routes1.begin(), routes1.end());
     std::sort(routes2.begin(), routes2.end());
     EXPECT_EQ(routes1, routes2);
@@ -371,8 +530,8 @@
 TEST_P(AudioCoreModule, GetAudioRoutesAreValid) {
     std::vector<AudioRoute> routes;
     {
-        Status status = module->getAudioRoutes(&routes);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioRoutes(&routes);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     for (const auto& route : routes) {
         std::set<int32_t> sources(route.sourcePortIds.begin(), route.sourcePortIds.end());
@@ -389,8 +548,8 @@
     ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
     std::vector<AudioRoute> routes;
     {
-        Status status = module->getAudioRoutes(&routes);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioRoutes(&routes);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     for (const auto& route : routes) {
         EXPECT_EQ(1, portIds.count(route.sinkPortId))
@@ -401,11 +560,37 @@
     }
 }
 
+TEST_P(AudioCoreModule, GetAudioRoutesForAudioPort) {
+    std::set<int32_t> portIds;
+    ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+    if (portIds.empty()) {
+        GTEST_SKIP() << "No ports in the module.";
+    }
+    for (const auto portId : portIds) {
+        std::vector<AudioRoute> routes;
+        ScopedAStatus status = module->getAudioRoutesForAudioPort(portId, &routes);
+        EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status;
+        for (const auto& r : routes) {
+            if (r.sinkPortId != portId) {
+                const auto& srcs = r.sourcePortIds;
+                EXPECT_TRUE(std::find(srcs.begin(), srcs.end(), portId) != srcs.end())
+                        << " port ID " << portId << " does not used by the route " << r.toString();
+            }
+        }
+    }
+    for (const auto portId : GetNonExistentIds(portIds)) {
+        std::vector<AudioRoute> routes;
+        ScopedAStatus status = module->getAudioRoutesForAudioPort(portId, &routes);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
+                << status << " returned for port ID " << portId;
+    }
+}
+
 TEST_P(AudioCoreModule, CheckDevicePorts) {
     std::vector<AudioPort> ports;
     {
-        Status status = module->getAudioPorts(&ports);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioPorts(&ports);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     std::optional<int32_t> defaultOutput, defaultInput;
     std::set<AudioDevice> inputs, outputs;
@@ -453,8 +638,8 @@
 TEST_P(AudioCoreModule, CheckMixPorts) {
     std::vector<AudioPort> ports;
     {
-        Status status = module->getAudioPorts(&ports);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioPorts(&ports);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     std::optional<int32_t> primaryMixPort;
     constexpr int primaryOutputFlag = 1 << static_cast<int>(AudioOutputFlags::PRIMARY);
@@ -482,33 +667,88 @@
     }
     for (const auto portId : portIds) {
         AudioPort port;
-        Status status = module->getAudioPort(portId, &port);
-        EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioPort(portId, &port);
+        EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status;
         EXPECT_EQ(portId, port.id);
     }
-    for (const auto portId : getNonExistentIds(portIds)) {
+    for (const auto portId : GetNonExistentIds(portIds)) {
         AudioPort port;
-        Status status = module->getAudioPort(portId, &port);
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        ScopedAStatus status = module->getAudioPort(portId, &port);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " returned for port ID " << portId;
     }
 }
 
+TEST_P(AudioCoreModule, SetUpModuleConfig) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    // Send the module config to logcat to facilitate failures investigation.
+    LOG(INFO) << "SetUpModuleConfig: " << moduleConfig->toString();
+}
+
+// Verify that HAL module reports for a connected device port at least one non-dynamic profile,
+// that is, a profile with actual supported configuration.
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, GetAudioPortWithExternalDevices) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+    if (ports.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    for (const auto& port : ports) {
+        AudioPort portWithData = port;
+        portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+                GenerateUniqueDeviceAddress();
+        WithDevicePortConnectedState portConnected(portWithData);
+        ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+        const int32_t connectedPortId = portConnected.getId();
+        ASSERT_NE(portWithData.id, connectedPortId);
+        ASSERT_EQ(portWithData.ext.getTag(), portConnected.get().ext.getTag());
+        EXPECT_EQ(portWithData.ext.get<AudioPortExt::Tag::device>().device,
+                  portConnected.get().ext.get<AudioPortExt::Tag::device>().device);
+        // Verify that 'getAudioPort' and 'getAudioPorts' return the same connected port.
+        AudioPort connectedPort;
+        ScopedAStatus status = module->getAudioPort(connectedPortId, &connectedPort);
+        EXPECT_EQ(EX_NONE, status.getExceptionCode())
+                << status << " returned for getAudioPort port ID " << connectedPortId;
+        EXPECT_EQ(portConnected.get(), connectedPort);
+        const auto& portProfiles = connectedPort.profiles;
+        EXPECT_NE(0, portProfiles.size())
+                << "Connected port has no profiles: " << connectedPort.toString();
+        const auto dynamicProfileIt =
+                std::find_if(portProfiles.begin(), portProfiles.end(), [](const auto& profile) {
+                    return profile.format.type == AudioFormatType::DEFAULT;
+                });
+        EXPECT_EQ(portProfiles.end(), dynamicProfileIt) << "Connected port contains dynamic "
+                                                        << "profiles: " << connectedPort.toString();
+
+        std::vector<AudioPort> allPorts;
+        {
+            ScopedAStatus status = module->getAudioPorts(&allPorts);
+            ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
+        }
+        const auto allPortsIt = findById(allPorts, connectedPortId);
+        EXPECT_NE(allPorts.end(), allPortsIt);
+        if (allPortsIt != allPorts.end()) {
+            EXPECT_EQ(portConnected.get(), *allPortsIt);
+        }
+    }
+}
+
 TEST_P(AudioCoreModule, OpenStreamInvalidPortConfigId) {
     std::set<int32_t> portConfigIds;
     ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
-    for (const auto portConfigId : getNonExistentIds(portConfigIds)) {
+    for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
         {
-            sp<IStreamIn> stream;
-            Status status = module->openInputStream(portConfigId, {}, &stream);
-            EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+            std::shared_ptr<IStreamIn> stream;
+            ScopedAStatus status = module->openInputStream(portConfigId, {}, &stream);
+            EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                     << status << " openInputStream returned for port config ID " << portConfigId;
             EXPECT_EQ(nullptr, stream);
         }
         {
-            sp<IStreamOut> stream;
-            Status status = module->openOutputStream(portConfigId, {}, {}, &stream);
-            EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+            std::shared_ptr<IStreamOut> stream;
+            ScopedAStatus status = module->openOutputStream(portConfigId, {}, {}, &stream);
+            EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                     << status << " openOutputStream returned for port config ID " << portConfigId;
             EXPECT_EQ(nullptr, stream);
         }
@@ -525,8 +765,8 @@
     ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
     std::vector<AudioPortConfig> portConfigs;
     {
-        Status status = module->getAudioPortConfigs(&portConfigs);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioPortConfigs(&portConfigs);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     for (const auto& config : portConfigs) {
         EXPECT_EQ(1, portIds.count(config.portId))
@@ -537,9 +777,9 @@
 TEST_P(AudioCoreModule, ResetAudioPortConfigInvalidId) {
     std::set<int32_t> portConfigIds;
     ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
-    for (const auto portConfigId : getNonExistentIds(portConfigIds)) {
-        Status status = module->resetAudioPortConfig(portConfigId);
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+    for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
+        ScopedAStatus status = module->resetAudioPortConfig(portConfigId);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " returned for port config ID " << portConfigId;
     }
 }
@@ -549,19 +789,19 @@
 TEST_P(AudioCoreModule, ResetAudioPortConfigToInitialValue) {
     std::vector<AudioPortConfig> portConfigsBefore;
     {
-        Status status = module->getAudioPortConfigs(&portConfigsBefore);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioPortConfigs(&portConfigsBefore);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     // TODO: Change port configs according to port profiles.
     for (const auto& c : portConfigsBefore) {
-        Status status = module->resetAudioPortConfig(c.id);
-        EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
+        ScopedAStatus status = module->resetAudioPortConfig(c.id);
+        EXPECT_EQ(EX_NONE, status.getExceptionCode())
                 << status << " returned for port config ID " << c.id;
     }
     std::vector<AudioPortConfig> portConfigsAfter;
     {
-        Status status = module->getAudioPortConfigs(&portConfigsAfter);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+        ScopedAStatus status = module->getAudioPortConfigs(&portConfigsAfter);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
     }
     for (const auto& c : portConfigsBefore) {
         auto afterIt = findById<AudioPortConfig>(portConfigsAfter, c.id);
@@ -584,8 +824,8 @@
     portConfig.portId = srcMixPort.value().id;
     {
         bool applied = true;
-        Status status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
-        ASSERT_EQ(Status::EX_NONE, status.exceptionCode())
+        ScopedAStatus status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode())
                 << status << "; Config: " << portConfig.toString();
         EXPECT_FALSE(applied);
     }
@@ -608,44 +848,40 @@
     EXPECT_EQ(suggestedConfig.flags.value(), appliedConfig.flags.value());
 }
 
+TEST_P(AudioCoreModule, SetAllAttachedDevicePortConfigs) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    ASSERT_NO_FATAL_FAILURE(ApplyEveryConfig(moduleConfig->getPortConfigsForAttachedDevicePorts()));
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, SetAllExternalDevicePortConfigs) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+    if (ports.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    for (const auto& port : ports) {
+        WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
+        ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+        ASSERT_NO_FATAL_FAILURE(
+                ApplyEveryConfig(moduleConfig->getPortConfigsForDevicePort(portConnected.get())));
+    }
+}
+
 TEST_P(AudioCoreModule, SetAllStaticAudioPortConfigs) {
     ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
-    const auto allPortConfigs = moduleConfig->getPortConfigsForMixPorts();
-    for (const auto& config : allPortConfigs) {
-        ASSERT_NE(0, config.portId);
-        WithAudioPortConfig portConfig(config);
-        ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
-        EXPECT_EQ(config.portId, portConfig.get().portId);
-        std::vector<AudioPortConfig> retrievedPortConfigs;
-        {
-            Status status = module->getAudioPortConfigs(&retrievedPortConfigs);
-            ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
-        }
-        const int32_t portConfigId = portConfig.getId();
-        auto configIt = std::find_if(
-                retrievedPortConfigs.begin(), retrievedPortConfigs.end(),
-                [&portConfigId](const auto& retrConf) { return retrConf.id == portConfigId; });
-        EXPECT_NE(configIt, retrievedPortConfigs.end())
-                << "Port config id returned by setAudioPortConfig: " << portConfigId
-                << " is not found in the list returned by getPortConfigsForMixPorts";
-        if (configIt != retrievedPortConfigs.end()) {
-            EXPECT_EQ(portConfig.get(), *configIt)
-                    << "Port config returned by getPortConfigsForMixPorts: " << configIt->toString()
-                    << " is not the same as returned by setAudioPortConfig: "
-                    << portConfig.get().toString();
-        }
-    }
+    ASSERT_NO_FATAL_FAILURE(ApplyEveryConfig(moduleConfig->getPortConfigsForMixPorts()));
 }
 
 TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortId) {
     std::set<int32_t> portIds;
     ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
-    for (const auto portId : getNonExistentIds(portIds)) {
+    for (const auto portId : GetNonExistentIds(portIds)) {
         AudioPortConfig portConfig, suggestedConfig;
         bool applied;
         portConfig.portId = portId;
-        Status status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        ScopedAStatus status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " returned for port ID " << portId;
         EXPECT_FALSE(suggestedConfig.format.has_value());
         EXPECT_FALSE(suggestedConfig.channelMask.has_value());
@@ -656,12 +892,12 @@
 TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortConfigId) {
     std::set<int32_t> portConfigIds;
     ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
-    for (const auto portConfigId : getNonExistentIds(portConfigIds)) {
+    for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
         AudioPortConfig portConfig, suggestedConfig;
         bool applied;
         portConfig.id = portConfigId;
-        Status status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        ScopedAStatus status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " returned for port config ID " << portConfigId;
         EXPECT_FALSE(suggestedConfig.format.has_value());
         EXPECT_FALSE(suggestedConfig.channelMask.has_value());
@@ -669,6 +905,203 @@
     }
 }
 
+TEST_P(AudioCoreModule, TryConnectMissingDevice) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+    if (ports.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    AudioPort ignored;
+    WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(debug);
+    doNotSimulateConnections.flags().simulateDeviceConnections = false;
+    ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get()));
+    for (const auto& port : ports) {
+        AudioPort portWithData = port;
+        portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+                GenerateUniqueDeviceAddress();
+        ScopedAStatus status = module->connectExternalDevice(portWithData, &ignored);
+        EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
+                << status << " returned for static port " << portWithData.toString();
+    }
+}
+
+TEST_P(AudioCoreModule, TryChangingConnectionSimulationMidway) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+    if (ports.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    WithDevicePortConnectedState portConnected(*ports.begin(), GenerateUniqueDeviceAddress());
+    ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+    ModuleDebug midwayDebugChange = debug.flags();
+    midwayDebugChange.simulateDeviceConnections = false;
+    ScopedAStatus status = module->setModuleDebug(midwayDebugChange);
+    EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
+            << status << " returned when trying to disable connections simulation "
+            << "while having a connected device";
+}
+
+TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceInvalidPorts) {
+    AudioPort ignored;
+    std::set<int32_t> portIds;
+    ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+    for (const auto portId : GetNonExistentIds(portIds)) {
+        AudioPort invalidPort;
+        invalidPort.id = portId;
+        ScopedAStatus status = module->connectExternalDevice(invalidPort, &ignored);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
+                << status << " returned for port ID " << portId << " when setting CONNECTED state";
+        status = module->disconnectExternalDevice(portId);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
+                << status << " returned for port ID " << portId
+                << " when setting DISCONNECTED state";
+    }
+
+    std::vector<AudioPort> ports;
+    {
+        ScopedAStatus status = module->getAudioPorts(&ports);
+        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
+    }
+    for (const auto& port : ports) {
+        if (port.ext.getTag() != AudioPortExt::Tag::device) {
+            ScopedAStatus status = module->connectExternalDevice(port, &ignored);
+            EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
+                    << status << " returned for non-device port ID " << port.id
+                    << " when setting CONNECTED state";
+            status = module->disconnectExternalDevice(port.id);
+            EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
+                    << status << " returned for non-device port ID " << port.id
+                    << " when setting DISCONNECTED state";
+        } else {
+            const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
+            if (devicePort.device.type.connection.empty()) {
+                ScopedAStatus status = module->connectExternalDevice(port, &ignored);
+                EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
+                        << status << " returned for permanently attached device port ID " << port.id
+                        << " when setting CONNECTED state";
+                status = module->disconnectExternalDevice(port.id);
+                EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
+                        << status << " returned for permanently attached device port ID " << port.id
+                        << " when setting DISCONNECTED state";
+            }
+        }
+    }
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceTwice) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    AudioPort ignored;
+    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+    if (ports.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    for (const auto& port : ports) {
+        ScopedAStatus status = module->disconnectExternalDevice(port.id);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
+                << status << " returned when disconnecting already disconnected device port ID "
+                << port.id;
+        AudioPort portWithData = port;
+        portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+                GenerateUniqueDeviceAddress();
+        WithDevicePortConnectedState portConnected(portWithData);
+        ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+        status = module->connectExternalDevice(portConnected.get(), &ignored);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
+                << status << " returned when trying to connect a connected device port "
+                << portConnected.get().toString();
+        status = module->connectExternalDevice(portWithData, &ignored);
+        EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
+                << status << " returned when connecting again the external device "
+                << portWithData.ext.get<AudioPortExt::Tag::device>().device.toString();
+        if (status.getExceptionCode() == EX_NONE) {
+            ADD_FAILURE() << "Returned connected port " << ignored.toString() << " for template "
+                          << portWithData.toString();
+        }
+    }
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, DisconnectExternalDeviceNonResetPortConfig) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+    if (ports.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    for (const auto& port : ports) {
+        WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
+        ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+        const auto portConfig = moduleConfig->getSingleConfigForDevicePort(portConnected.get());
+        {
+            WithAudioPortConfig config(portConfig);
+            // Note: if SetUp fails, check the status of 'GetAudioPortWithExternalDevices' test.
+            // Our test assumes that 'getAudioPort' returns at least one profile, and it
+            // is not a dynamic profile.
+            ASSERT_NO_FATAL_FAILURE(config.SetUp(module.get()));
+            ScopedAStatus status = module->disconnectExternalDevice(portConnected.getId());
+            EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
+                    << status << " returned when trying to disconnect device port ID " << port.id
+                    << " with active configuration " << config.getId();
+        }
+    }
+}
+
+TEST_P(AudioCoreModule, ExternalDevicePortRoutes) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+    if (ports.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    for (const auto& port : ports) {
+        std::vector<AudioRoute> routesBefore;
+        {
+            ScopedAStatus status = module->getAudioRoutes(&routesBefore);
+            ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
+        }
+
+        int32_t connectedPortId;
+        {
+            WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
+            ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+            connectedPortId = portConnected.getId();
+            std::vector<AudioRoute> connectedPortRoutes;
+            {
+                ScopedAStatus status =
+                        module->getAudioRoutesForAudioPort(connectedPortId, &connectedPortRoutes);
+                ASSERT_EQ(EX_NONE, status.getExceptionCode())
+                        << status << " returned when retrieving routes for connected port id "
+                        << connectedPortId;
+            }
+            // There must be routes for the port to be useful.
+            if (connectedPortRoutes.empty()) {
+                std::vector<AudioRoute> allRoutes;
+                ScopedAStatus status = module->getAudioRoutes(&allRoutes);
+                ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
+                ADD_FAILURE() << " no routes returned for the connected port "
+                              << portConnected.get().toString()
+                              << "; all routes: " << android::internal::ToString(allRoutes);
+            }
+        }
+        std::vector<AudioRoute> ignored;
+        ScopedAStatus status = module->getAudioRoutesForAudioPort(connectedPortId, &ignored);
+        ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
+                << status << " returned when retrieving routes for released connected port id "
+                << connectedPortId;
+
+        std::vector<AudioRoute> routesAfter;
+        {
+            ScopedAStatus status = module->getAudioRoutes(&routesAfter);
+            ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
+        }
+        ASSERT_EQ(routesBefore.size(), routesAfter.size())
+                << "Sizes of audio route arrays do not match after creating and "
+                << "releasing a connected port";
+        std::sort(routesBefore.begin(), routesBefore.end());
+        std::sort(routesAfter.begin(), routesAfter.end());
+        EXPECT_EQ(routesBefore, routesAfter);
+    }
+}
+
 template <typename Stream>
 class AudioStream : public AudioCoreModule {
   public:
@@ -684,14 +1117,14 @@
         if (!portConfig.has_value()) {
             GTEST_SKIP() << "No mix port for attached devices";
         }
-        sp<Stream> heldStream;
+        std::shared_ptr<Stream> heldStream;
         {
             WithStream<Stream> stream(portConfig.value());
             ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get()));
-            heldStream = stream.get();
+            heldStream = stream.getSharedPointer();
         }
-        Status status = heldStream->close();
-        EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+        ScopedAStatus status = heldStream->close();
+        EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
                 << status << " when closing the stream twice";
     }
 
@@ -728,12 +1161,11 @@
                     ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get()));
                 } else {
                     ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
-                    Status status = stream.SetUpNoChecks(module.get());
-                    EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+                    ScopedAStatus status = stream.SetUpNoChecks(module.get());
+                    EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
                             << status << " open" << direction(true)
-                            << "Stream"
-                               " returned for port config ID "
-                            << stream.getPortId() << ", maxOpenStreamCount is " << maxStreamCount;
+                            << "Stream returned for port config ID " << stream.getPortId()
+                            << ", maxOpenStreamCount is " << maxStreamCount;
                 }
             }
         }
@@ -751,8 +1183,8 @@
         }
         WithStream<Stream> stream(portConfig.value());
         ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
-        Status status = stream.SetUpNoChecks(module.get());
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        ScopedAStatus status = stream.SetUpNoChecks(module.get());
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " open" << direction(true) << "Stream returned for port config ID "
                 << stream.getPortId();
         EXPECT_EQ(nullptr, stream.get());
@@ -773,8 +1205,8 @@
         }
         WithStream<Stream> stream(portConfig.value());
         ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get()));
-        Status status = module->resetAudioPortConfig(stream.getPortId());
-        EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+        ScopedAStatus status = module->resetAudioPortConfig(stream.getPortId());
+        EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
                 << status << " returned for port config ID " << stream.getPortId();
     }
 
@@ -782,8 +1214,8 @@
         WithStream<Stream> stream1(portConfig);
         ASSERT_NO_FATAL_FAILURE(stream1.SetUp(module.get()));
         WithStream<Stream> stream2;
-        Status status = stream2.SetUpNoChecks(module.get(), stream1.getPortConfig());
-        EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+        ScopedAStatus status = stream2.SetUpNoChecks(module.get(), stream1.getPortConfig());
+        EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
                 << status << " when opening " << direction(false)
                 << " stream twice for the same port config ID " << stream1.getPortId();
     }
@@ -816,7 +1248,7 @@
     auto primaryPortIt = std::find_if(mixPorts.begin(), mixPorts.end(), [](const AudioPort& port) {
         constexpr int primaryOutputFlag = 1 << static_cast<int>(AudioOutputFlags::PRIMARY);
         return port.flags.getTag() == AudioIoFlags::Tag::output &&
-               ((port.flags.get<AudioIoFlags::Tag::output>() & primaryOutputFlag) != 0);
+               (port.flags.get<AudioIoFlags::Tag::output>() & primaryOutputFlag) != 0;
     });
     if (primaryPortIt == mixPorts.end()) {
         GTEST_SKIP() << "No primary mix port";
@@ -829,6 +1261,31 @@
     EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
 }
 
+TEST_P(AudioStreamOut, RequireOffloadInfo) {
+    const auto mixPorts = moduleConfig->getMixPorts(false);
+    auto offloadPortIt = std::find_if(mixPorts.begin(), mixPorts.end(), [&](const AudioPort& port) {
+        constexpr int compressOffloadFlag = 1
+                                            << static_cast<int>(AudioOutputFlags::COMPRESS_OFFLOAD);
+        return port.flags.getTag() == AudioIoFlags::Tag::output &&
+               (port.flags.get<AudioIoFlags::Tag::output>() & compressOffloadFlag) != 0 &&
+               !moduleConfig->getAttachedSinkDevicesPortsForMixPort(port).empty();
+    });
+    if (offloadPortIt == mixPorts.end()) {
+        GTEST_SKIP()
+                << "No mix port for compressed offload that could be routed to attached devices";
+    }
+    const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, *offloadPortIt);
+    ASSERT_TRUE(portConfig.has_value())
+            << "No profiles specified for the compressed offload mix port";
+    std::shared_ptr<IStreamOut> ignored;
+    ScopedAStatus status = module->openOutputStream(portConfig.value().id,
+                                                    GenerateSourceMetadata(portConfig.value()),
+                                                    {} /* offloadInfo */, &ignored);
+    EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
+            << status
+            << " returned when no offload info is provided for a compressed offload mix port";
+}
+
 // Tests specific to audio patches. The fixure class is named 'AudioModulePatch'
 // to avoid clashing with 'AudioPatch' class.
 class AudioModulePatch : public AudioCoreModule {
@@ -847,8 +1304,8 @@
         AudioPatch patch;
         patch.sourcePortConfigIds = sources;
         patch.sinkPortConfigIds = sinks;
-        Status status = module->setAudioPatch(patch, &patch);
-        ASSERT_EQ(expectedException, status.exceptionCode())
+        ScopedAStatus status = module->setAudioPatch(patch, &patch);
+        ASSERT_EQ(expectedException, status.getExceptionCode())
                 << status << ": patch source ids: " << android::internal::ToString(sources)
                 << "; sink ids: " << android::internal::ToString(sinks);
     }
@@ -867,8 +1324,8 @@
                                           patch.get().sinkPortConfigIds.begin(),
                                           patch.get().sinkPortConfigIds.end());
         for (const auto portConfigId : sourceAndSinkPortConfigIds) {
-            Status status = module->resetAudioPortConfig(portConfigId);
-            EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+            ScopedAStatus status = module->resetAudioPortConfig(portConfigId);
+            EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
                     << status << " returned for port config ID " << portConfigId;
         }
     }
@@ -887,22 +1344,22 @@
             ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
         }
         EXPECT_NO_FATAL_FAILURE(
-                SetInvalidPatchHelper(Status::EX_ILLEGAL_ARGUMENT, {}, {sinkPortConfig.getId()}));
+                SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {}, {sinkPortConfig.getId()}));
         EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(
-                Status::EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId(), srcPortConfig.getId()},
+                EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId(), srcPortConfig.getId()},
                 {sinkPortConfig.getId()}));
         EXPECT_NO_FATAL_FAILURE(
-                SetInvalidPatchHelper(Status::EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()}, {}));
+                SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()}, {}));
         EXPECT_NO_FATAL_FAILURE(
-                SetInvalidPatchHelper(Status::EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()},
+                SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()},
                                       {sinkPortConfig.getId(), sinkPortConfig.getId()}));
 
         std::set<int32_t> portConfigIds;
         ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
-        for (const auto portConfigId : getNonExistentIds(portConfigIds)) {
-            EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(
-                    Status::EX_ILLEGAL_ARGUMENT, {portConfigId}, {sinkPortConfig.getId()}));
-            EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(Status::EX_ILLEGAL_ARGUMENT,
+        for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
+            EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {portConfigId},
+                                                          {sinkPortConfig.getId()}));
+            EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT,
                                                           {srcPortConfig.getId()}, {portConfigId}));
         }
     }
@@ -914,8 +1371,8 @@
         }
         WithAudioPatch patch(srcSinkPair.value().first, srcSinkPair.value().second);
         ASSERT_NO_FATAL_FAILURE(patch.SetUpPortConfigs(module.get()));
-        Status status = patch.SetUpNoChecks(module.get());
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+        ScopedAStatus status = patch.SetUpNoChecks(module.get());
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << ": when setting up a patch from "
                 << srcSinkPair.value().first.toString() << " to "
                 << srcSinkPair.value().second.toString() << " that does not have a route";
@@ -928,11 +1385,12 @@
         }
         for (const auto& srcSinkGroup : srcSinkGroups) {
             const auto& route = srcSinkGroup.first;
-            std::vector<WithAudioPatch> patches;
+            std::vector<std::unique_ptr<WithAudioPatch>> patches;
             for (const auto& srcSink : srcSinkGroup.second) {
                 if (!route.isExclusive) {
-                    patches.emplace_back(srcSink.first, srcSink.second);
-                    EXPECT_NO_FATAL_FAILURE(patches[patches.size() - 1].SetUp(module.get()));
+                    patches.push_back(
+                            std::make_unique<WithAudioPatch>(srcSink.first, srcSink.second));
+                    EXPECT_NO_FATAL_FAILURE(patches[patches.size() - 1]->SetUp(module.get()));
                 } else {
                     WithAudioPatch patch(srcSink.first, srcSink.second);
                     EXPECT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
@@ -969,11 +1427,12 @@
         // Then use the same patch setting, except for having an invalid ID.
         std::set<int32_t> patchIds;
         ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
-        for (const auto patchId : getNonExistentIds(patchIds)) {
+        for (const auto patchId : GetNonExistentIds(patchIds)) {
             AudioPatch patchWithNonExistendId = patch.get();
             patchWithNonExistendId.id = patchId;
-            Status status = module->setAudioPatch(patchWithNonExistendId, &patchWithNonExistendId);
-            EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+            ScopedAStatus status =
+                    module->setAudioPatch(patchWithNonExistendId, &patchWithNonExistendId);
+            EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                     << status << " returned for patch ID " << patchId;
         }
     }
@@ -995,9 +1454,9 @@
 TEST_P(AudioModulePatch, ResetInvalidPatchId) {
     std::set<int32_t> patchIds;
     ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
-    for (const auto patchId : getNonExistentIds(patchIds)) {
-        Status status = module->resetAudioPatch(patchId);
-        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+    for (const auto patchId : GetNonExistentIds(patchIds)) {
+        ScopedAStatus status = module->resetAudioPatch(patchId);
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
                 << status << " returned for patch ID " << patchId;
     }
 }
@@ -1019,9 +1478,26 @@
                          android::PrintInstanceNameToString);
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModulePatch);
 
+class TestExecutionTracer : public ::testing::EmptyTestEventListener {
+  public:
+    void OnTestStart(const ::testing::TestInfo& test_info) override {
+        TraceTestState("Started", test_info);
+    }
+
+    void OnTestEnd(const ::testing::TestInfo& test_info) override {
+        TraceTestState("Completed", test_info);
+    }
+
+  private:
+    static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info) {
+        LOG(INFO) << state << " " << test_info.test_suite_name() << "::" << test_info.name();
+    }
+};
+
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
-    ProcessState::self()->setThreadPoolMaxThreadCount(1);
-    ProcessState::self()->startThreadPool();
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
 }
diff --git a/audio/common/all-versions/test/utility/src/ValidateXml.cpp b/audio/common/all-versions/test/utility/src/ValidateXml.cpp
index f111c01..4d6f003 100644
--- a/audio/common/all-versions/test/utility/src/ValidateXml.cpp
+++ b/audio/common/all-versions/test/utility/src/ValidateXml.cpp
@@ -63,11 +63,8 @@
         xmlSetGenericErrorFunc(this, errorCb);
     }
     ~Libxml2Global() {
-        // TODO: check if all those cleanup are needed
         xmlSetGenericErrorFunc(nullptr, nullptr);
-        xmlSchemaCleanupTypes();
         xmlCleanupParser();
-        xmlCleanupThreads();
     }
 
     const std::string& getErrors() { return errors; }
diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
index dfc2386..44d3cbd 100644
--- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#include <fstream>
+#include <numeric>
+
 #include <android-base/chrono_utils.h>
 
 #include "Generators.h"
@@ -517,20 +520,10 @@
     }
 
     bool canQueryPresentationPosition() const {
-        auto maybeSinkAddress =
-                getCachedPolicyConfig().getSinkDeviceForMixPort(getDeviceName(), getMixPortName());
-        // Returning 'true' when no sink is found so the test can fail later with a more clear
-        // problem description.
-        return !maybeSinkAddress.has_value() ||
-               !xsd::isTelephonyDevice(maybeSinkAddress.value().deviceType);
+        return !xsd::isTelephonyDevice(address.deviceType);
     }
 
     void createPatchIfNeeded() {
-        auto maybeSinkAddress =
-                getCachedPolicyConfig().getSinkDeviceForMixPort(getDeviceName(), getMixPortName());
-        ASSERT_TRUE(maybeSinkAddress.has_value())
-                << "No sink device found for mix port " << getMixPortName() << " (module "
-                << getDeviceName() << ")";
         if (areAudioPatchesSupported()) {
             AudioPortConfig source;
             source.base.format.value(getConfig().base.format);
@@ -540,13 +533,13 @@
             source.ext.mix().ioHandle = helper.getIoHandle();
             source.ext.mix().useCase.stream({});
             AudioPortConfig sink;
-            sink.ext.device(maybeSinkAddress.value());
+            sink.ext.device(address);
             EXPECT_OK(getDevice()->createAudioPatch(hidl_vec<AudioPortConfig>{source},
                                                     hidl_vec<AudioPortConfig>{sink},
                                                     returnIn(res, mPatchHandle)));
             mHasPatch = res == Result::OK;
         } else {
-            EXPECT_OK(stream->setDevices({maybeSinkAddress.value()}));
+            EXPECT_OK(stream->setDevices({address}));
         }
     }
 
@@ -556,10 +549,6 @@
                 EXPECT_OK(getDevice()->releaseAudioPatch(mPatchHandle));
                 mHasPatch = false;
             }
-        } else {
-            if (stream) {
-                EXPECT_OK(stream->setDevices({address}));
-            }
         }
     }
 
@@ -575,16 +564,22 @@
         // Sometimes HAL doesn't have enough information until the audio data actually gets
         // consumed by the hardware.
         bool timedOut = false;
-        res = Result::INVALID_STATE;
-        for (android::base::Timer elapsed;
-             res != Result::OK && !writer.hasError() &&
-             !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
-            usleep(kWriteDurationUs);
-            ASSERT_OK(stream->getPresentationPosition(returnIn(res, framesInitial, ts)));
-            ASSERT_RESULT(okOrInvalidState, res);
+        if (!firstPosition || *firstPosition == std::numeric_limits<uint64_t>::max()) {
+            res = Result::INVALID_STATE;
+            for (android::base::Timer elapsed;
+                 res != Result::OK && !writer.hasError() &&
+                 !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
+                usleep(kWriteDurationUs);
+                ASSERT_OK(stream->getPresentationPosition(returnIn(res, framesInitial, ts)));
+                ASSERT_RESULT(okOrInvalidState, res);
+            }
+            ASSERT_FALSE(writer.hasError());
+            ASSERT_FALSE(timedOut);
+        } else {
+            // Use `firstPosition` instead of querying it from the HAL. This is used when
+            // `waitForPresentationPositionAdvance` is called in a loop.
+            framesInitial = *firstPosition;
         }
-        ASSERT_FALSE(writer.hasError());
-        ASSERT_FALSE(timedOut);
 
         uint64_t frames = framesInitial;
         for (android::base::Timer elapsed;
@@ -646,7 +641,7 @@
     ASSERT_OK(stream->standby());
     writer.resume();
 
-    uint64_t frames;
+    uint64_t frames = std::numeric_limits<uint64_t>::max();
     ASSERT_NO_FATAL_FAILURE(waitForPresentationPositionAdvance(writer, &frames));
     EXPECT_GT(frames, framesInitial);
 
@@ -691,24 +686,12 @@
         InputStreamTest::TearDown();
     }
 
-    bool canQueryCapturePosition() const {
-        auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort(
-                getDeviceName(), getMixPortName());
-        // Returning 'true' when no source is found so the test can fail later with a more clear
-        // problem description.
-        return !maybeSourceAddress.has_value() ||
-               !xsd::isTelephonyDevice(maybeSourceAddress.value().deviceType);
-    }
+    bool canQueryCapturePosition() const { return !xsd::isTelephonyDevice(address.deviceType); }
 
     void createPatchIfNeeded() {
-        auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort(
-                getDeviceName(), getMixPortName());
-        ASSERT_TRUE(maybeSourceAddress.has_value())
-                << "No source device found for mix port " << getMixPortName() << " (module "
-                << getDeviceName() << ")";
         if (areAudioPatchesSupported()) {
             AudioPortConfig source;
-            source.ext.device(maybeSourceAddress.value());
+            source.ext.device(address);
             AudioPortConfig sink;
             sink.base.format.value(getConfig().base.format);
             sink.base.sampleRateHz.value(getConfig().base.sampleRateHz);
@@ -721,20 +704,14 @@
                                                     returnIn(res, mPatchHandle)));
             mHasPatch = res == Result::OK;
         } else {
-            EXPECT_OK(stream->setDevices({maybeSourceAddress.value()}));
+            EXPECT_OK(stream->setDevices({address}));
         }
     }
 
     void releasePatchIfNeeded() {
-        if (getDevice()) {
-            if (areAudioPatchesSupported() && mHasPatch) {
-                EXPECT_OK(getDevice()->releaseAudioPatch(mPatchHandle));
-                mHasPatch = false;
-            }
-        } else {
-            if (stream) {
-                EXPECT_OK(stream->setDevices({address}));
-            }
+        if (getDevice() && areAudioPatchesSupported() && mHasPatch) {
+            EXPECT_OK(getDevice()->releaseAudioPatch(mPatchHandle));
+            mHasPatch = false;
         }
     }
 
@@ -864,14 +841,8 @@
     }
     ASSERT_OK(res);
 
-    auto maybeSourceAddress =
-            getCachedPolicyConfig().getSourceDeviceForMixPort(getDeviceName(), getMixPortName());
-    ASSERT_TRUE(maybeSourceAddress.has_value())
-            << "No source device found for mix port " << getMixPortName() << " (module "
-            << getDeviceName() << ")";
-
     for (auto microphone : microphones) {
-        if (microphone.deviceAddress == maybeSourceAddress.value()) {
+        if (microphone.deviceAddress == address) {
             StreamReader reader(stream.get(), stream->getBufferSize());
             ASSERT_TRUE(reader.start());
             reader.pause();  // This ensures that at least one read has happened.
@@ -889,3 +860,100 @@
                         ::testing::ValuesIn(getBuiltinMicConfigParameters()),
                         &DeviceConfigParameterToString);
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MicrophoneInfoInputStreamTest);
+
+static const std::vector<DeviceConfigParameter>& getOutputDeviceCompressedConfigParameters(
+        const AudioConfigBase& configToMatch) {
+    static const std::vector<DeviceConfigParameter> parameters = [&] {
+        auto allParams = getOutputDeviceConfigParameters();
+        std::vector<DeviceConfigParameter> compressedParams;
+        std::copy_if(allParams.begin(), allParams.end(), std::back_inserter(compressedParams),
+                     [&](auto cfg) {
+                         if (std::get<PARAM_CONFIG>(cfg).base != configToMatch) return false;
+                         const auto& flags = std::get<PARAM_FLAGS>(cfg);
+                         return std::find_if(flags.begin(), flags.end(), [](const auto& flag) {
+                                    return flag ==
+                                           toString(xsd::AudioInOutFlag::
+                                                            AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+                                }) != flags.end();
+                     });
+        return compressedParams;
+    }();
+    return parameters;
+}
+
+class CompressedOffloadOutputStreamTest : public PcmOnlyConfigOutputStreamTest {
+  public:
+    void loadData(const std::string& fileName, std::vector<uint8_t>* data) {
+        std::ifstream is(fileName, std::ios::in | std::ios::binary);
+        ASSERT_TRUE(is.good()) << "Failed to open file " << fileName;
+        is.seekg(0, is.end);
+        data->reserve(data->size() + is.tellg());
+        is.seekg(0, is.beg);
+        data->insert(data->end(), std::istreambuf_iterator<char>(is),
+                     std::istreambuf_iterator<char>());
+        ASSERT_TRUE(!is.fail()) << "Failed to read from file " << fileName;
+    }
+};
+
+TEST_P(CompressedOffloadOutputStreamTest, Mp3FormatGaplessOffload) {
+    doc::test("Check that compressed offload mix ports for MP3 implement gapless offload");
+    const auto& flags = getOutputFlags();
+    if (std::find_if(flags.begin(), flags.end(), [](const auto& flag) {
+            return flag == toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD);
+        }) == flags.end()) {
+        GTEST_SKIP() << "Compressed offload mix port does not support gapless offload";
+    }
+    // FIXME: The presentation position is not updated if there is no zero padding in data.
+    std::vector<uint8_t> offloadData(stream->getBufferSize());
+    ASSERT_NO_FATAL_FAILURE(loadData("/data/local/tmp/sine882hz3s.mp3", &offloadData));
+    ASSERT_FALSE(offloadData.empty());
+    ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded());
+    const int presentationeEndPrecisionMs = 1000;
+    const int sampleRate = 44100;
+    const int significantSampleNumber = (presentationeEndPrecisionMs * sampleRate) / 1000;
+    const int delay = 576 + 1000;
+    const int padding = 756 + 1000;
+    const int durationMs = 3000 - 44;
+    // StreamWriter plays 'offloadData' in a loop, possibly using multiple calls to 'write',
+    // this depends on the relative sizes of 'offloadData' and the HAL buffer. Writer calls
+    // 'onDataWrap' callback each time it wraps around the buffer.
+    StreamWriter writer(
+            stream.get(), stream->getBufferSize(), std::move(offloadData), [&]() /* onDataWrap */ {
+                Parameters::set(stream,
+                                {{AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, std::to_string(delay)},
+                                 {AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, std::to_string(padding)}});
+                stream->drain(AudioDrain::EARLY_NOTIFY);
+            });
+    ASSERT_TRUE(writer.start());
+    ASSERT_TRUE(writer.waitForAtLeastOneCycle());
+    // Decrease the volume since the test plays a loud sine wave.
+    ASSERT_OK(stream->setVolume(0.1, 0.1));
+    // How many times to loop the track so that the sum of gapless delay and padding from
+    // the first presentation end to the last is at least 'presentationeEndPrecisionMs'.
+    const int playbackNumber = (int)(significantSampleNumber / ((float)delay + padding) + 1);
+    std::vector<float> presentationEndTimes;
+    uint64_t previousPosition = std::numeric_limits<uint64_t>::max();
+    for (int i = 0; i < playbackNumber; ++i) {
+        const auto start = std::chrono::steady_clock::now();
+        ASSERT_NO_FATAL_FAILURE(
+                waitForPresentationPositionAdvance(writer, &previousPosition, &previousPosition));
+        presentationEndTimes.push_back(std::chrono::duration_cast<std::chrono::milliseconds>(
+                                               std::chrono::steady_clock::now() - start)
+                                               .count());
+    }
+    const float avgDuration =
+            std::accumulate(presentationEndTimes.begin(), presentationEndTimes.end(), 0.0) /
+            presentationEndTimes.size();
+    EXPECT_NEAR(durationMs, avgDuration, presentationeEndPrecisionMs * 0.1);
+    writer.stop();
+    releasePatchIfNeeded();
+}
+
+INSTANTIATE_TEST_CASE_P(
+        CompressedOffloadOutputStream, CompressedOffloadOutputStreamTest,
+        ::testing::ValuesIn(getOutputDeviceCompressedConfigParameters(AudioConfigBase{
+                .format = xsd::toString(xsd::AudioFormat::AUDIO_FORMAT_MP3),
+                .sampleRateHz = 44100,
+                .channelMask = xsd::toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO)})),
+        &DeviceConfigParameterToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CompressedOffloadOutputStreamTest);
diff --git a/audio/core/all-versions/vts/functional/7.0/Generators.cpp b/audio/core/all-versions/vts/functional/7.0/Generators.cpp
index f936d0a..8b955b6 100644
--- a/audio/core/all-versions/vts/functional/7.0/Generators.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/Generators.cpp
@@ -57,9 +57,6 @@
 
 static std::tuple<std::vector<AudioInOutFlag>, bool> generateOutFlags(
         const xsd::MixPorts::MixPort& mixPort) {
-    static const std::vector<AudioInOutFlag> offloadFlags = {
-            toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
-            toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_DIRECT)};
     std::vector<AudioInOutFlag> flags;
     bool isOffload = false;
     if (mixPort.hasFlags()) {
@@ -67,14 +64,10 @@
         isOffload = std::find(xsdFlags.begin(), xsdFlags.end(),
                               xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) !=
                     xsdFlags.end();
-        if (!isOffload) {
-            for (auto flag : xsdFlags) {
-                if (flag != xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_PRIMARY) {
-                    flags.push_back(toString(flag));
-                }
+        for (auto flag : xsdFlags) {
+            if (flag != xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_PRIMARY) {
+                flags.push_back(toString(flag));
             }
-        } else {
-            flags = offloadFlags;
         }
     }
     return {flags, isOffload};
@@ -85,10 +78,10 @@
             .base = base,
             .streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC),
             .usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
-            .bitRatePerSecond = 320,
+            .bitRatePerSecond = 192,  // as in sine882hz3s.mp3
             .durationMicroseconds = -1,
             .bitWidth = 16,
-            .bufferSize = 256  // arbitrary value
+            .bufferSize = 72000  // 3 seconds at 192 kbps, as in sine882hz3s.mp3
     };
 }
 
@@ -100,11 +93,10 @@
         if (!module || !module->getFirstMixPorts()) break;
         for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
             if (mixPort.getRole() != xsd::Role::source) continue;  // not an output profile
-            if (getCachedPolicyConfig()
-                        .getAttachedSinkDeviceForMixPort(moduleName, mixPort.getName())
-                        .empty()) {
-                continue;  // no attached device
-            }
+            const auto attachedDeviceAddress =
+                    getCachedPolicyConfig().getDeviceAddressOfSinkDeviceAttachedToMixPort(
+                            moduleName, mixPort.getName());
+            if (!attachedDeviceAddress.has_value()) continue;
             auto [flags, isOffload] = generateOutFlags(mixPort);
             for (const auto& profile : mixPort.getProfile()) {
                 if (!profile.hasFormat() || !profile.hasSamplingRates() ||
@@ -118,7 +110,8 @@
                     if (isOffload) {
                         config.offloadInfo.info(generateOffloadInfo(config.base));
                     }
-                    result.emplace_back(device, mixPort.getName(), config, flags);
+                    result.emplace_back(device, mixPort.getName(), attachedDeviceAddress.value(),
+                                        config, flags);
                     if (oneProfilePerDevice) break;
                 }
                 if (oneProfilePerDevice) break;
@@ -162,13 +155,16 @@
                             profile.getFormat(),
                             static_cast<uint32_t>(profile.getSamplingRates()[0]),
                             toString(profile.getChannelMasks()[0])};
+                    DeviceAddress defaultDevice = {
+                            toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT), {}};
                     {
                         AudioConfig config{.base = validBase};
                         config.base.channelMask = "random_string";
                         if (isOffload) {
                             config.offloadInfo.info(generateOffloadInfo(validBase));
                         }
-                        result.emplace_back(device, mixPort.getName(), config, validFlags);
+                        result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                            validFlags);
                     }
                     {
                         AudioConfig config{.base = validBase};
@@ -176,7 +172,8 @@
                         if (isOffload) {
                             config.offloadInfo.info(generateOffloadInfo(validBase));
                         }
-                        result.emplace_back(device, mixPort.getName(), config, validFlags);
+                        result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                            validFlags);
                     }
                     if (generateInvalidFlags) {
                         AudioConfig config{.base = validBase};
@@ -184,32 +181,37 @@
                             config.offloadInfo.info(generateOffloadInfo(validBase));
                         }
                         std::vector<AudioInOutFlag> flags = {"random_string", ""};
-                        result.emplace_back(device, mixPort.getName(), config, flags);
+                        result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                            flags);
                     }
                     if (isOffload) {
                         {
                             AudioConfig config{.base = validBase};
                             config.offloadInfo.info(generateOffloadInfo(validBase));
                             config.offloadInfo.info().base.channelMask = "random_string";
-                            result.emplace_back(device, mixPort.getName(), config, validFlags);
+                            result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                                validFlags);
                         }
                         {
                             AudioConfig config{.base = validBase};
                             config.offloadInfo.info(generateOffloadInfo(validBase));
                             config.offloadInfo.info().base.format = "random_string";
-                            result.emplace_back(device, mixPort.getName(), config, validFlags);
+                            result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                                validFlags);
                         }
                         {
                             AudioConfig config{.base = validBase};
                             config.offloadInfo.info(generateOffloadInfo(validBase));
                             config.offloadInfo.info().streamType = "random_string";
-                            result.emplace_back(device, mixPort.getName(), config, validFlags);
+                            result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                                validFlags);
                         }
                         {
                             AudioConfig config{.base = validBase};
                             config.offloadInfo.info(generateOffloadInfo(validBase));
                             config.offloadInfo.info().usage = "random_string";
-                            result.emplace_back(device, mixPort.getName(), config, validFlags);
+                            result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                                validFlags);
                         }
                         hasOffloadConfig = true;
                     } else {
@@ -233,11 +235,10 @@
         if (!module || !module->getFirstMixPorts()) break;
         for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
             if (mixPort.getRole() != xsd::Role::sink) continue;  // not an input profile
-            if (getCachedPolicyConfig()
-                        .getAttachedSourceDeviceForMixPort(moduleName, mixPort.getName())
-                        .empty()) {
-                continue;  // no attached device
-            }
+            const auto attachedDeviceAddress =
+                    getCachedPolicyConfig().getDeviceAddressOfSourceDeviceAttachedToMixPort(
+                            moduleName, mixPort.getName());
+            if (!attachedDeviceAddress.has_value()) continue;
             std::vector<AudioInOutFlag> flags;
             if (mixPort.hasFlags()) {
                 std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(),
@@ -250,7 +251,8 @@
                 auto configs = combineAudioConfig(profile.getChannelMasks(),
                                                   profile.getSamplingRates(), profile.getFormat());
                 for (const auto& config : configs) {
-                    result.emplace_back(device, mixPort.getName(), config, flags);
+                    result.emplace_back(device, mixPort.getName(), attachedDeviceAddress.value(),
+                                        config, flags);
                     if (oneProfilePerDevice) break;
                 }
                 if (oneProfilePerDevice) break;
@@ -298,20 +300,25 @@
                             profile.getFormat(),
                             static_cast<uint32_t>(profile.getSamplingRates()[0]),
                             toString(profile.getChannelMasks()[0])};
+                    DeviceAddress defaultDevice = {
+                            toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT), {}};
                     {
                         AudioConfig config{.base = validBase};
                         config.base.channelMask = "random_string";
-                        result.emplace_back(device, mixPort.getName(), config, validFlags);
+                        result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                            validFlags);
                     }
                     {
                         AudioConfig config{.base = validBase};
                         config.base.format = "random_string";
-                        result.emplace_back(device, mixPort.getName(), config, validFlags);
+                        result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                            validFlags);
                     }
                     if (generateInvalidFlags) {
                         AudioConfig config{.base = validBase};
                         std::vector<AudioInOutFlag> flags = {"random_string", ""};
-                        result.emplace_back(device, mixPort.getName(), config, flags);
+                        result.emplace_back(device, mixPort.getName(), defaultDevice, config,
+                                            flags);
                     }
                     hasConfig = true;
                     break;
diff --git a/audio/core/all-versions/vts/functional/7.0/PolicyConfig.h b/audio/core/all-versions/vts/functional/7.0/PolicyConfig.h
index 4aea503..c1d5669 100644
--- a/audio/core/all-versions/vts/functional/7.0/PolicyConfig.h
+++ b/audio/core/all-versions/vts/functional/7.0/PolicyConfig.h
@@ -61,6 +61,18 @@
     const std::set<std::string>& getModulesWithDevicesNames() const {
         return mModulesWithDevicesNames;
     }
+    std::optional<DeviceAddress> getDeviceAddressOfSinkDeviceAttachedToMixPort(
+            const std::string& moduleName, const std::string& mixPortName) const {
+        const auto attachedDevicePort = getAttachedSinkDeviceForMixPort(moduleName, mixPortName);
+        if (attachedDevicePort.empty()) return {};
+        return getDeviceAddressOfDevicePort(moduleName, attachedDevicePort);
+    }
+    std::optional<DeviceAddress> getDeviceAddressOfSourceDeviceAttachedToMixPort(
+            const std::string& moduleName, const std::string& mixPortName) const {
+        const auto attachedDevicePort = getAttachedSourceDeviceForMixPort(moduleName, mixPortName);
+        if (attachedDevicePort.empty()) return {};
+        return getDeviceAddressOfDevicePort(moduleName, attachedDevicePort);
+    }
     std::string getAttachedSinkDeviceForMixPort(const std::string& moduleName,
                                                 const std::string& mixPortName) const {
         return findAttachedDevice(getAttachedDevices(moduleName),
@@ -84,8 +96,6 @@
     const std::vector<std::string>& getAttachedDevices(const std::string& moduleName) const;
     std::optional<DeviceAddress> getDeviceAddressOfDevicePort(
             const std::string& moduleName, const std::string& devicePortName) const;
-    std::string getDevicePortTagNameFromType(const std::string& moduleName,
-                                             const AudioDevice& deviceType) const;
     std::set<std::string> getSinkDevicesForMixPort(const std::string& moduleName,
                                                    const std::string& mixPortName) const;
     std::set<std::string> getSourceDevicesForMixPort(const std::string& moduleName,
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index c757032..5b0a7f2 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -190,6 +190,7 @@
     ],
     data: [
         ":audio_policy_configuration_V7_0",
+        "data/sine882hz3s.mp3",
     ],
     // Use test_config for vts suite.
     // TODO(b/146104851): Add auto-gen rules and remove it.
@@ -223,6 +224,7 @@
     ],
     data: [
         ":audio_policy_configuration_V7_1",
+        "data/sine882hz3s.mp3",
     ],
     // Use test_config for vts suite.
     // TODO(b/146104851): Add auto-gen rules and remove it.
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 38e9e5f..6c5584d 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -617,7 +617,8 @@
                     std::get<PARAM_FLAGS>(info.param)));
 #elif MAJOR_VERSION >= 7
     const auto configPart =
-            std::to_string(config.base.sampleRateHz) + "_" +
+            ::testing::PrintToString(std::get<PARAM_ATTACHED_DEV_ADDR>(info.param).deviceType) +
+            "_" + std::to_string(config.base.sampleRateHz) + "_" +
             // The channel masks and flags are vectors of strings, just need to sanitize them.
             SanitizeStringForGTestName(::testing::PrintToString(config.base.channelMask)) + "_" +
             SanitizeStringForGTestName(::testing::PrintToString(std::get<PARAM_FLAGS>(info.param)));
@@ -658,6 +659,9 @@
                 std::get<INDEX_OUTPUT>(std::get<PARAM_FLAGS>(GetParam())));
     }
 #elif MAJOR_VERSION >= 7
+    DeviceAddress getAttachedDeviceAddress() const {
+        return std::get<PARAM_ATTACHED_DEV_ADDR>(GetParam());
+    }
     hidl_vec<AudioInOutFlag> getInputFlags() const { return std::get<PARAM_FLAGS>(GetParam()); }
     hidl_vec<AudioInOutFlag> getOutputFlags() const { return std::get<PARAM_FLAGS>(GetParam()); }
 #endif
@@ -933,6 +937,14 @@
 
     StreamWriter(IStreamOut* stream, size_t bufferSize)
         : mStream(stream), mBufferSize(bufferSize), mData(mBufferSize) {}
+    StreamWriter(IStreamOut* stream, size_t bufferSize, std::vector<uint8_t>&& data,
+                 std::function<void()> onDataWrap)
+        : mStream(stream),
+          mBufferSize(bufferSize),
+          mData(std::move(data)),
+          mOnDataWrap(onDataWrap) {
+        ALOGW("StreamWriter data size: %d", (int)mData.size());
+    }
     ~StreamWriter() {
         stop();
         if (mEfGroup) {
@@ -998,9 +1010,11 @@
             ALOGE("command message queue write failed");
             return false;
         }
-        const size_t dataSize = std::min(mData.size(), mDataMQ->availableToWrite());
-        bool success = mDataMQ->write(mData.data(), dataSize);
+        const size_t dataSize = std::min(mData.size() - mDataPosition, mDataMQ->availableToWrite());
+        bool success = mDataMQ->write(mData.data() + mDataPosition, dataSize);
         ALOGE_IF(!success, "data message queue write failed");
+        mDataPosition += dataSize;
+        if (mDataPosition >= mData.size()) mDataPosition = 0;
         mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
 
         uint32_t efState = 0;
@@ -1026,6 +1040,7 @@
             ALOGE("bad wait status: %d", ret);
             success = false;
         }
+        if (success && mDataPosition == 0) mOnDataWrap();
         return success;
     }
 
@@ -1033,6 +1048,8 @@
     IStreamOut* const mStream;
     const size_t mBufferSize;
     std::vector<uint8_t> mData;
+    std::function<void()> mOnDataWrap = []() {};
+    size_t mDataPosition = 0;
     std::unique_ptr<CommandMQ> mCommandMQ;
     std::unique_ptr<DataMQ> mDataMQ;
     std::unique_ptr<StatusMQ> mStatusMQ;
@@ -1047,7 +1064,7 @@
 #if MAJOR_VERSION <= 6
         address.device = AudioDevice::OUT_DEFAULT;
 #elif MAJOR_VERSION >= 7
-        address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT);
+        address = getAttachedDeviceAddress();
 #endif
         const AudioConfig& config = getConfig();
         auto flags = getOutputFlags();
@@ -1243,16 +1260,11 @@
 #if MAJOR_VERSION <= 6
         address.device = AudioDevice::IN_DEFAULT;
 #elif MAJOR_VERSION >= 7
-        auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort(
-                getDeviceName(), getMixPortName());
+        address = getAttachedDeviceAddress();
         auto& metadata = initMetadata.tracks[0];
-        if (maybeSourceAddress.has_value() &&
-            !xsd::isTelephonyDevice(maybeSourceAddress.value().deviceType)) {
-            address = maybeSourceAddress.value();
+        if (!xsd::isTelephonyDevice(address.deviceType)) {
             metadata.source = toString(xsd::AudioSource::AUDIO_SOURCE_UNPROCESSED);
             metadata.channelMask = getConfig().base.channelMask;
-        } else {
-            address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT);
         }
 #if MAJOR_VERSION == 7 && MINOR_VERSION >= 1
         auto flagsIt = std::find(flags.begin(), flags.end(),
diff --git a/audio/core/all-versions/vts/functional/AudioTestDefinitions.h b/audio/core/all-versions/vts/functional/AudioTestDefinitions.h
index 802b87b..3de06c3 100644
--- a/audio/core/all-versions/vts/functional/AudioTestDefinitions.h
+++ b/audio/core/all-versions/vts/functional/AudioTestDefinitions.h
@@ -39,9 +39,10 @@
         std::variant<android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::AudioInputFlag,
                      android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::AudioOutputFlag>>;
 #elif MAJOR_VERSION >= 7
-enum { PARAM_DEVICE, PARAM_PORT_NAME, PARAM_CONFIG, PARAM_FLAGS };
+enum { PARAM_DEVICE, PARAM_PORT_NAME, PARAM_ATTACHED_DEV_ADDR, PARAM_CONFIG, PARAM_FLAGS };
 using DeviceConfigParameter =
         std::tuple<DeviceParameter, std::string,
+                   android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::DeviceAddress,
                    android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::AudioConfig,
                    std::vector<android::hardware::audio::CORE_TYPES_CPP_VERSION::AudioInOutFlag>>;
 #endif
diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml
index f0e2695..8da5744 100644
--- a/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml
+++ b/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml
@@ -29,6 +29,7 @@
         <option name="cleanup" value="true" />
         <option name="push" value="VtsHalAudioV7_0TargetTest->/data/local/tmp/VtsHalAudioV7_0TargetTest" />
         <option name="push" value="audio_policy_configuration_V7_0.xsd->/data/local/tmp/audio_policy_configuration_V7_0.xsd" />
+        <option name="push" value="sine882hz3s.mp3->/data/local/tmp/sine882hz3s.mp3" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV7_1TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV7_1TargetTest.xml
index 7ce1477..227df18 100644
--- a/audio/core/all-versions/vts/functional/VtsHalAudioV7_1TargetTest.xml
+++ b/audio/core/all-versions/vts/functional/VtsHalAudioV7_1TargetTest.xml
@@ -29,6 +29,8 @@
         <option name="cleanup" value="true" />
         <option name="push" value="VtsHalAudioV7_1TargetTest->/data/local/tmp/VtsHalAudioV7_1TargetTest" />
         <option name="push" value="audio_policy_configuration_V7_1.xsd->/data/local/tmp/audio_policy_configuration_V7_1.xsd" />
+        <option name="push" value="sine882hz3s.mp3->/data/local/tmp/sine882hz3s.mp3" />
+
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
diff --git a/audio/core/all-versions/vts/functional/data/sine882hz3s.mp3 b/audio/core/all-versions/vts/functional/data/sine882hz3s.mp3
new file mode 100644
index 0000000..0604f9b
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/data/sine882hz3s.mp3
Binary files differ
diff --git a/audio/policy/1.0/xml/api/current.txt b/audio/policy/1.0/xml/api/current.txt
index 1478381..0b77d45 100644
--- a/audio/policy/1.0/xml/api/current.txt
+++ b/audio/policy/1.0/xml/api/current.txt
@@ -232,12 +232,12 @@
 
   public class ValueType {
     ctor public ValueType();
-    method public int getAndroid_type();
+    method public String getAndroid_type();
     method public String getLiteral();
-    method public int getNumerical();
-    method public void setAndroid_type(int);
+    method public long getNumerical();
+    method public void setAndroid_type(String);
     method public void setLiteral(String);
-    method public void setNumerical(int);
+    method public void setNumerical(long);
   }
 
   public class ValuesType {
diff --git a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
index 852ea77..3ce12e7 100644
--- a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
+++ b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
@@ -189,10 +189,20 @@
     </xs:complexType>
     <xs:complexType name="valueType">
         <xs:attribute name="literal" type="xs:string" use="required"/>
-        <xs:attribute name="numerical" type="xs:int" use="required"/>
-        <xs:attribute name="android_type" type="xs:int" use="optional"/>
+        <xs:attribute name="numerical" type="xs:long" use="required"/>
+        <xs:attribute name="android_type" type="longDecimalOrHexType" use="optional"/>
     </xs:complexType>
 
+    <xs:simpleType name="longDecimalOrHexType">
+      <xs:union memberTypes="xs:long longHexType" />
+    </xs:simpleType>
+
+    <xs:simpleType name="longHexType">
+      <xs:restriction base="xs:string">
+        <xs:pattern value="0x[0-9A-Fa-f]{1,16}"/>
+      </xs:restriction>
+    </xs:simpleType>
+
     <xs:complexType name="attributesRefType">
         <xs:sequence>
             <xs:element name="Attributes" type="AttributesType" minOccurs="1" maxOccurs="1"/>
diff --git a/authsecret/aidl/Android.bp b/authsecret/aidl/Android.bp
index 432c1b9..90e128d 100644
--- a/authsecret/aidl/Android.bp
+++ b/authsecret/aidl/Android.bp
@@ -16,11 +16,6 @@
         java: {
             platform_apis: true,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions: ["1"],
 }
diff --git a/automotive/OWNERS b/automotive/OWNERS
index 43c5f3e..09e257c 100644
--- a/automotive/OWNERS
+++ b/automotive/OWNERS
@@ -1,6 +1 @@
-pirozzoj@google.com
-twasilczyk@google.com
-krachuri@google.com
-gurunagarajan@google.com
-keunyoung@google.com
-felipeal@google.com
+include platform/packages/services/Car:/OWNERS
diff --git a/automotive/audiocontrol/OWNERS b/automotive/audiocontrol/OWNERS
new file mode 100644
index 0000000..f55eff3
--- /dev/null
+++ b/automotive/audiocontrol/OWNERS
@@ -0,0 +1 @@
+oscarazu@google.com
diff --git a/automotive/can/OWNERS b/automotive/can/OWNERS
new file mode 100644
index 0000000..ffa4828
--- /dev/null
+++ b/automotive/can/OWNERS
@@ -0,0 +1,3 @@
+kevinme@google.com
+chrisweir@google.com
+twasilczyk@google.com
diff --git a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
index 09e1088..9c6c573 100644
--- a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
+++ b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
@@ -19,9 +19,11 @@
 
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
+#include <aidl/android/hardware/automotive/evs/BnEvsEnumeratorStatusCallback.h>
 #include <aidl/android/hardware/automotive/evs/BufferDesc.h>
 #include <aidl/android/hardware/automotive/evs/CameraDesc.h>
 #include <aidl/android/hardware/automotive/evs/CameraParam.h>
+#include <aidl/android/hardware/automotive/evs/DeviceStatus.h>
 #include <aidl/android/hardware/automotive/evs/DisplayDesc.h>
 #include <aidl/android/hardware/automotive/evs/DisplayState.h>
 #include <aidl/android/hardware/automotive/evs/EvsEventDesc.h>
@@ -30,6 +32,7 @@
 #include <aidl/android/hardware/automotive/evs/IEvsCamera.h>
 #include <aidl/android/hardware/automotive/evs/IEvsDisplay.h>
 #include <aidl/android/hardware/automotive/evs/IEvsEnumerator.h>
+#include <aidl/android/hardware/automotive/evs/IEvsEnumeratorStatusCallback.h>
 #include <aidl/android/hardware/automotive/evs/IEvsUltrasonicsArray.h>
 #include <aidl/android/hardware/automotive/evs/ParameterRange.h>
 #include <aidl/android/hardware/automotive/evs/Stream.h>
@@ -77,11 +80,11 @@
 } RawStreamConfig;
 constexpr size_t kStreamCfgSz = sizeof(RawStreamConfig) / sizeof(int32_t);
 
-}  // namespace
-
+using ::aidl::android::hardware::automotive::evs::BnEvsEnumeratorStatusCallback;
 using ::aidl::android::hardware::automotive::evs::BufferDesc;
 using ::aidl::android::hardware::automotive::evs::CameraDesc;
 using ::aidl::android::hardware::automotive::evs::CameraParam;
+using ::aidl::android::hardware::automotive::evs::DeviceStatus;
 using ::aidl::android::hardware::automotive::evs::DisplayDesc;
 using ::aidl::android::hardware::automotive::evs::DisplayState;
 using ::aidl::android::hardware::automotive::evs::EvsEventDesc;
@@ -90,6 +93,7 @@
 using ::aidl::android::hardware::automotive::evs::IEvsCamera;
 using ::aidl::android::hardware::automotive::evs::IEvsDisplay;
 using ::aidl::android::hardware::automotive::evs::IEvsEnumerator;
+using ::aidl::android::hardware::automotive::evs::IEvsEnumeratorStatusCallback;
 using ::aidl::android::hardware::automotive::evs::IEvsUltrasonicsArray;
 using ::aidl::android::hardware::automotive::evs::ParameterRange;
 using ::aidl::android::hardware::automotive::evs::Stream;
@@ -99,6 +103,8 @@
 using ::aidl::android::hardware::graphics::common::PixelFormat;
 using std::chrono_literals::operator""s;
 
+}  // namespace
+
 // The main test class for EVS
 class EvsAidlTest : public ::testing::TestWithParam<std::string> {
   public:
@@ -239,6 +245,13 @@
         return targetCfg;
     }
 
+    class DeviceStatusCallback : public BnEvsEnumeratorStatusCallback {
+        ndk::ScopedAStatus deviceStatusChanged(const std::vector<DeviceStatus>&) override {
+            // This empty implementation returns always ok().
+            return ndk::ScopedAStatus::ok();
+        }
+    };
+
     // Every test needs access to the service
     std::shared_ptr<IEvsEnumerator> mEnumerator;
     // Empty unless/util loadCameraList() is called
@@ -528,7 +541,7 @@
         // Ask for a very large number of buffers in flight to ensure it errors correctly
         auto badResult = pCam->setMaxFramesInFlight(std::numeric_limits<int32_t>::max());
         EXPECT_TRUE(!badResult.isOk() && badResult.getServiceSpecificError() ==
-                                                 static_cast<int>(EvsResult::INVALID_ARG));
+                                                 static_cast<int>(EvsResult::BUFFER_NOT_AVAILABLE));
 
         // Now ask for exactly two buffers in flight as we'll test behavior in that case
         ASSERT_TRUE(pCam->setMaxFramesInFlight(kBuffersToHold).isOk());
@@ -2064,6 +2077,20 @@
     }
 }
 
+TEST_P(EvsAidlTest, DeviceStatusCallbackRegistration) {
+    std::shared_ptr<IEvsEnumeratorStatusCallback> cb =
+            ndk::SharedRefBase::make<DeviceStatusCallback>();
+    ndk::ScopedAStatus status = mEnumerator->registerStatusCallback(cb);
+    if (mIsHwModule) {
+        ASSERT_TRUE(status.isOk());
+    } else {
+        // A callback registration may fail if a HIDL EVS HAL implementation is
+        // running.
+        ASSERT_TRUE(status.isOk() ||
+                    status.getServiceSpecificError() == static_cast<int>(EvsResult::NOT_SUPPORTED));
+    }
+}
+
 /*
  * UltrasonicsArrayOpenClean:
  * Opens each ultrasonics arrays reported by the enumerator and then explicitly closes it via a
diff --git a/automotive/occupant_awareness/aidl/Android.bp b/automotive/occupant_awareness/aidl/Android.bp
index 6ddc127..1a8124c 100644
--- a/automotive/occupant_awareness/aidl/Android.bp
+++ b/automotive/occupant_awareness/aidl/Android.bp
@@ -23,11 +23,6 @@
                 "com.android.car.framework",
             ],
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions: ["1"],
 }
diff --git a/automotive/sv/OWNERS b/automotive/sv/OWNERS
new file mode 100644
index 0000000..af6788b
--- /dev/null
+++ b/automotive/sv/OWNERS
@@ -0,0 +1 @@
+tanmayp@google.com
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 9edd2bd..edc8949 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -1118,6 +1118,19 @@
                         },
                 .initialValue = {.stringValue = {"Test"}},
         },
+        // This property is later defined in the AIDL VHAL interface. However, HIDL VHAL might
+        // require support for this property to meet EU regulation.
+        {
+                .config =
+                        {
+                                // GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT
+                                .prop = 0x11400F47,
+                                .access = VehiclePropertyAccess::READ,
+                                .changeMode = VehiclePropertyChangeMode::STATIC,
+                        },
+                // GsrComplianceRequirementType::GSR_COMPLIANCE_REQUIRED_V1
+                .initialValue = {.int32Values = {1}},
+        },
 #ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
         // Vendor propetry for E2E ClusterHomeService testing.
         {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
index d35792d..74f5a7a 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
@@ -141,7 +141,7 @@
 TEST_F(DefaultVhalImplTest, testListProperties) {
     std::vector<VehiclePropConfig> configs = mHal->listProperties();
 
-    EXPECT_EQ((size_t)122, configs.size());
+    EXPECT_EQ((size_t)123, configs.size());
 }
 
 TEST_F(DefaultVhalImplTest, testGetDefaultPropertyFloat) {
@@ -402,7 +402,7 @@
     gotValue->timestamp = 0;
 
     std::string infoMake = toString(*gotValue);
-    EXPECT_THAT(std::string(buf), HasSubstr(infoMake));
+    EXPECT_THAT(std::string(buf, sizeof(buf)), HasSubstr(infoMake));
 }
 
 TEST_F(DefaultVhalImplTest, testSetPropInvalidAreaId) {
diff --git a/automotive/vehicle/README.md b/automotive/vehicle/README.md
new file mode 100644
index 0000000..e0f03e2
--- /dev/null
+++ b/automotive/vehicle/README.md
@@ -0,0 +1,26 @@
+# Vehicle Hardware Abstraction Layer (VHAL)
+---
+
+This directory stores the VHAL interface definition and VHAL reference
+implementation.
+
+## 2.0 (deprecated)
+
+HIDL based VHAL interface and reference implementation. 
+
+## aidl
+
+AIDL based VHAL interfadce and reference implementation.
+
+## proto
+
+Protobuf used to pass message between emulator VHAL and emulator.
+
+## tools
+
+Dev tools related to VHAL.
+
+## vts
+
+VTS test for VHAL. The VTS test works for both AIDL and HIDL VHAL
+implementation. Vendor implementation of VHAL must passes VTS.
diff --git a/automotive/vehicle/aidl/README.md b/automotive/vehicle/aidl/README.md
new file mode 100644
index 0000000..09f03b4
--- /dev/null
+++ b/automotive/vehicle/aidl/README.md
@@ -0,0 +1,23 @@
+# AIDL Vehicle Hardware Abstraction Layer (VHAL)
+---
+
+This directory stores the AIDL VHAL interface and reference implementation.
+
+## aidl_api
+
+Auto-generated current and previous versions of AIDL VHAL api.
+
+## aidl_test
+
+Contains a test to test that all HIDL VHAL properties are supported in
+AIDL VHAL.
+
+## android
+
+Contains AIDL VHAL interface definition. The main interface file is
+`android/hardware/automotive/vehicle/IVehicle.aidl`.
+
+## impl
+
+Reference implementation for AIDL VHAL and useful libraries for implementing
+vendor AIDL VHAL.
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/.hash b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/.hash
index 7bb15e8..f478504 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/.hash
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/.hash
@@ -1 +1 @@
-38469e5a0359c95015bea304c463b686cf4ee9ca
+8610b651e162c614a97542d6f4ed039c969823e5
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
index 7e48eba..d7b874a 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
@@ -36,5 +36,5 @@
 enum VehicleApPowerStateConfigFlag {
   ENABLE_DEEP_SLEEP_FLAG = 1,
   CONFIG_SUPPORT_TIMER_POWER_ON_FLAG = 2,
-  ENABLE_HIBERNATION_FLAG = 3,
+  ENABLE_HIBERNATION_FLAG = 4,
 }
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GsrComplianceRequirementType.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GsrComplianceRequirementType.aidl
new file mode 100644
index 0000000..0d3a061
--- /dev/null
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GsrComplianceRequirementType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum GsrComplianceRequirementType {
+  GSR_COMPLIANCE_NOT_REQUIRED = 0,
+  GSR_COMPLIANCE_REQUIRED_THROUGH_SYSTEM_IMAGE = 1,
+}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
index 7e48eba..d7b874a 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
@@ -36,5 +36,5 @@
 enum VehicleApPowerStateConfigFlag {
   ENABLE_DEEP_SLEEP_FLAG = 1,
   CONFIG_SUPPORT_TIMER_POWER_ON_FLAG = 2,
-  ENABLE_HIBERNATION_FLAG = 3,
+  ENABLE_HIBERNATION_FLAG = 4,
 }
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 04f8fa3..2d0cde5 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -206,4 +206,5 @@
   EV_REGENERATIVE_BRAKING_STATE = 289410884,
   TRAILER_PRESENT = 289410885,
   VEHICLE_CURB_WEIGHT = 289410886,
+  GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT = 289410887,
 }
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GsrComplianceRequirementType.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GsrComplianceRequirementType.aidl
new file mode 100644
index 0000000..e0609d5
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GsrComplianceRequirementType.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * Used by GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT to indicate what
+ * kind of general safety regulation compliance requirement is enforced.
+ */
+@VintfStability
+@Backing(type="int")
+enum GsrComplianceRequirementType {
+    /**
+     * GSR compliance is not required.
+     */
+    GSR_COMPLIANCE_NOT_REQUIRED = 0,
+    /**
+     * GSR compliance is required through system image.
+     */
+    GSR_COMPLIANCE_REQUIRED_THROUGH_SYSTEM_IMAGE = 1,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
index 4d8e2f5..8b0190ce 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
@@ -37,5 +37,5 @@
      * (via VehicleApPowerStateShutdownParam#CAN_HIBERNATE or
      *  VehicleApPowerStateShutdownParam#HIBERNATE_IMMEDIATELY flags)
      */
-    ENABLE_HIBERNATION_FLAG = 0x3,
+    ENABLE_HIBERNATION_FLAG = 0x4,
 }
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 727b949..15d8e58 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -2840,4 +2840,17 @@
     VEHICLE_CURB_WEIGHT = 0x0F46 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
 
+    /**
+     * EU's General security regulation compliance requirement.
+     *
+     * Returns whether general security regulation compliance is required, if
+     * so, what type of requirement.
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     * @data_enum GsrComplianceRequirementType
+     */
+    GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT = 0x0F47 + 0x10000000 + 0x01000000
+            + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+
 }
diff --git a/automotive/vehicle/aidl/impl/Android.bp b/automotive/vehicle/aidl/impl/Android.bp
index d24a739..73f7df0 100644
--- a/automotive/vehicle/aidl/impl/Android.bp
+++ b/automotive/vehicle/aidl/impl/Android.bp
@@ -19,10 +19,16 @@
 }
 
 cc_defaults {
+    name: "VehicleHalInterfaceDefaults",
+    static_libs: [
+        "android.hardware.automotive.vehicle-V2-ndk",
+    ],
+}
+
+cc_defaults {
     name: "VehicleHalDefaults",
     static_libs: [
         "android-automotive-large-parcelable-lib",
-        "android.hardware.automotive.vehicle-V1-ndk",
         "libmath",
     ],
     shared_libs: [
@@ -37,6 +43,7 @@
         "-Wthread-safety",
     ],
     defaults: [
+        "VehicleHalInterfaceDefaults",
         "android-automotive-large-parcelable-defaults",
     ],
 }
diff --git a/automotive/vehicle/aidl/impl/README.md b/automotive/vehicle/aidl/impl/README.md
new file mode 100644
index 0000000..121ffd1
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/README.md
@@ -0,0 +1,58 @@
+# AIDL VHAL libraries and reference implementation.
+---
+
+This directory stores the libraries useful for implementing vendor AIDL VHAL.
+This directory also stores a reference fake implementation for AIDL VHAL.
+
+## default_config
+
+Stores the default vehicle property configurations for reference vehicle HAL.
+Vendor implementation could copy this library but must update the configuration
+to meet their own requirements, e.g. enable or disable certain properties or
+update the initial value for certain properties.
+
+##	fake_impl
+
+Contains libraries used specifically for the fake reference VHAL implementation.
+These libraries are for test only and must not be directly used for vendor
+VHAL implementation.
+
+These libraries contain test-spcific logic and must not run directly on a real
+vehicle.
+
+## grpc
+
+Stores code for GRPC based VHAL implementation.
+
+## hardware
+
+Defines an interface `IVehicleHardware.h` which vendor must implement for
+vehicle-specific logic if they want to follow our reference VHAL design.
+
+## proto
+
+Stores Some protobuf files translated from AIDL VHAL interface types. These
+files are used in GRPC VHAL implementation.
+
+## utils
+
+Defines a library `VehicleHalUtils` which provides useful utility functions for
+VHAL implementation. Vendor VHAL could use this library.
+
+## vhal
+
+Defines a library `DefaultVehicleHal` which provides generic logic for all VHAL
+implementations (including reference VHAL). Vendor VHAL implementation could
+use this library, along with their own implementation for `IVehicleHardware`
+interface.
+
+Also defines a binary `android.hardware.automotive.vehicle@V1-default-service`
+which is the reference VHAL implementation. It implements `IVehicle.aidl`
+interface. It uses `DefaultVehicleHal`, along with `FakeVehicleHardware`
+(in fake_impl). It simulates the vehicle bus interaction by using an
+in-memory map. Meaning that all properties (except for some special ones) are
+just written into a hash map and read from a hash map without relying on any
+hardware. As a result, the reference implementation can run on emulator or
+any host environment.
+
+Vendor must not directly use the reference implementation for a real vehicle.
\ No newline at end of file
diff --git a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h b/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
index 5430f14..46b9a89 100644
--- a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
+++ b/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
@@ -36,6 +36,7 @@
 using ::aidl::android::hardware::automotive::vehicle::EvsServiceState;
 using ::aidl::android::hardware::automotive::vehicle::EvsServiceType;
 using ::aidl::android::hardware::automotive::vehicle::FuelType;
+using ::aidl::android::hardware::automotive::vehicle::GsrComplianceRequirementType;
 using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReport;
 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
@@ -173,6 +174,17 @@
 
         {.config =
                  {
+                         .prop = toInt(VehicleProperty::EV_BATTERY_DISPLAY_UNITS),
+                         .access = VehiclePropertyAccess::READ_WRITE,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .configArray = {toInt(VehicleUnit::WATT_HOUR),
+                                         toInt(VehicleUnit::AMPERE_HOURS),
+                                         toInt(VehicleUnit::KILOWATT_HOUR)},
+                 },
+         .initialValue = {.int32Values = {toInt(VehicleUnit::KILOWATT_HOUR)}}},
+
+        {.config =
+                 {
                          .prop = toInt(VehicleProperty::SEAT_OCCUPANCY),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -724,6 +736,16 @@
 
         {.config =
                  {
+                         .prop = toInt(VehicleProperty::ENGINE_COOLANT_TEMP),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+                         .minSampleRate = 1.0f,
+                         .maxSampleRate = 10.0f,
+                 },
+         .initialValue = {.floatValues = {75.0f}}},
+
+        {.config =
+                 {
                          .prop = toInt(VehicleProperty::ENGINE_OIL_LEVEL),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -835,7 +857,7 @@
         {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
                     .access = VehiclePropertyAccess::READ,
                     .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                    .configArray = {3}}},
+                    .configArray = {0}}},
 
         {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
                     .access = VehiclePropertyAccess::READ_WRITE,
@@ -893,14 +915,6 @@
 
         {.config =
                  {
-                         .prop = toInt(VehicleProperty::FOG_LIGHTS_STATE),
-                         .access = VehiclePropertyAccess::READ,
-                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                 },
-         .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
-
-        {.config =
-                 {
                          .prop = toInt(VehicleProperty::FRONT_FOG_LIGHTS_STATE),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -1245,6 +1259,19 @@
                                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
                         },
         },
+        {
+                .config =
+                        {
+                                .prop = toInt(
+                                        VehicleProperty::
+                                                GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT),
+                                .access = VehiclePropertyAccess::READ,
+                                .changeMode = VehiclePropertyChangeMode::STATIC,
+                        },
+                .initialValue = {.int32Values = {toInt(
+                                         GsrComplianceRequirementType::
+                                                 GSR_COMPLIANCE_REQUIRED_THROUGH_SYSTEM_IMAGE)}},
+        },
 #ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
         // Vendor propetry for E2E ClusterHomeService testing.
         {
diff --git a/automotive/vehicle/aidl/impl/fake_impl/README.md b/automotive/vehicle/aidl/impl/fake_impl/README.md
new file mode 100644
index 0000000..e86dcee
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/README.md
@@ -0,0 +1,28 @@
+# Fake reference AIDL VHAL implementation libraries
+---
+
+This directory stores libraries for implementing a fake reference AIDL VHAL.
+
+WARNING: All the libraries here are for TEST ONLY.
+
+## GeneratorHub
+
+Defines a library `FakeVehicleHalValueGenerators` that could generate fake
+vehicle property values for testing.
+
+## hardware
+
+Defines a fake implementation for device-specifc interface `IVehicleHardware`:
+`FakeVehicleHardware`. This implementation uses a in-memory map for storing
+property values and does not communicate with or depending on any specific
+vehicle bus.
+
+## obd2frame
+
+Defines a library `FakeObd2Frame` that generates fake OBD2 frame for OBD2
+properties.
+
+## userhal
+
+Defines a library `FakeUserHal` that emulates a real User HAL behavior by
+parsing debug commands.
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 7f9b63a..7c451fe 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -67,6 +67,7 @@
 
 using ::android::base::EqualsIgnoreCase;
 using ::android::base::Error;
+using ::android::base::GetIntProperty;
 using ::android::base::ParseFloat;
 using ::android::base::Result;
 using ::android::base::ScopedLockAssertion;
@@ -75,6 +76,7 @@
 
 const char* VENDOR_OVERRIDE_DIR = "/vendor/etc/automotive/vhaloverride/";
 const char* OVERRIDE_PROPERTY = "persist.vendor.vhal_init_value_override";
+const char* POWER_STATE_REQ_CONFIG_PROPERTY = "ro.vendor.fake_vhal.ap_power_state_req.config";
 
 // A list of supported options for "--set" command.
 const std::unordered_set<std::string> SET_PROP_OPTIONS = {
@@ -163,7 +165,10 @@
         VehiclePropConfig cfg = it.config;
         VehiclePropertyStore::TokenFunction tokenFunction = nullptr;
 
-        if (cfg.prop == OBD2_FREEZE_FRAME) {
+        if (cfg.prop == toInt(VehicleProperty::AP_POWER_STATE_REQ)) {
+            int config = GetIntProperty(POWER_STATE_REQ_CONFIG_PROPERTY, /*default_value=*/0);
+            cfg.configArray[0] = config;
+        } else if (cfg.prop == OBD2_FREEZE_FRAME) {
             tokenFunction = [](const VehiclePropValue& propValue) { return propValue.timestamp; };
         }
 
@@ -225,17 +230,16 @@
             [[fallthrough]];
         case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
             // CPMS is in WAIT_FOR_VHAL state, simply move to ON and send back to HAL.
-            // Must erase existing state because in the case when Car Service crashes, the power
-            // state would already be ON when we receive WAIT_FOR_VHAL and thus new property change
-            // event would be generated. However, Car Service always expect a property change event
-            // even though there is not actual state change.
-            mServerSidePropStore->removeValuesForProperty(
-                    toInt(VehicleProperty::AP_POWER_STATE_REQ));
             prop = createApPowerStateReq(VehicleApPowerStateReq::ON);
 
-            // ALWAYS update status for generated property value
+            // ALWAYS update status for generated property value, and force a property update event
+            // because in the case when Car Service crashes, the power state would already be ON
+            // when we receive WAIT_FOR_VHAL and thus new property change event would be generated.
+            // However, Car Service always expect a property change event even though there is no
+            // actual state change.
             if (auto writeResult =
-                        mServerSidePropStore->writeValue(std::move(prop), /*updateStatus=*/true);
+                        mServerSidePropStore->writeValue(std::move(prop), /*updateStatus=*/true,
+                                                         VehiclePropertyStore::EventMode::ALWAYS);
                 !writeResult.ok()) {
                 return StatusError(getErrorCode(writeResult))
                        << "failed to write AP_POWER_STATE_REQ into property store, error: "
@@ -1238,10 +1242,10 @@
             return;
         }
         result.value()->timestamp = elapsedRealtimeNano();
-        // Must remove the value before writing, otherwise, we would generate no update event since
-        // the value is the same.
-        mServerSidePropStore->removeValue(*result.value());
-        mServerSidePropStore->writeValue(std::move(result.value()));
+        // For continuous properties, we must generate a new onPropertyChange event periodically
+        // according to the sample rate.
+        mServerSidePropStore->writeValue(std::move(result.value()), /*updateStatus=*/true,
+                                         VehiclePropertyStore::EventMode::ALWAYS);
     });
     mRecurrentTimer->registerTimerCallback(interval, action);
     mRecurrentActions[propIdAreaId] = action;
diff --git a/automotive/vehicle/aidl/impl/utils/README.md b/automotive/vehicle/aidl/impl/utils/README.md
new file mode 100644
index 0000000..87bb7e3
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/utils/README.md
@@ -0,0 +1,62 @@
+# Utility classes for VHAL implementation
+---
+
+This directory stores utility classes for VHAL implementation. Vendor
+implementation could use utility classes from `common` folder in their
+VHAL implementation.
+
+## common
+
+Defines common utility libraries.
+
+### ConcurrentQueue
+
+Provides a thread-safe concurrent queue object. Useful for adding object to
+a queue in one thread (usually binder thread) and handle the objects in a
+separate handler thread.
+
+### ParcelableUtils
+
+Provides functions to convert between a regular parcelable and a
+`LargeParcelabe`.
+
+A `LargeParcelable` is a parcelable that marshals the payload
+into a shared memory file if the payload is too large to pass across binder.
+It is used to pass large data across binder. Before sending the data, VHAL
+impl should convert a regular parcelabe to a `LargeParcelable`. After receving
+data, VHAL impl should convert a `LargeParcelable` back to regular parcelabe.
+
+### PendingRequestPool
+
+Defines A class for managing pending requests and automatically call timeout
+callback if the request timed-out.
+
+### PropertyUtils
+
+Defines some useful constants.
+
+### RecurrentTimer
+
+Defines a thread-safe recurrent timer that can call a function periodically.
+
+### VehicleHalTypes
+
+Provides a header file that includes many commonly used header files. Useful
+when you are using multiple types defined in VHAL interface.
+
+### VehicleObjectPool
+
+Defines a reusable in-memory pool for `VehiclePropValue`.
+
+### VehiclePropertyStore
+
+Defines an in-memory map for storing vehicle properties. Allows easier insert,
+delete and lookup.
+
+### VehicleUtils
+
+Defines many useful utility functions.
+
+## test
+
+Defines utility libraries for test only.
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
index a7fcdcf..6af1223 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
@@ -26,6 +26,7 @@
 #include <aidl/android/hardware/automotive/vehicle/GetValueRequest.h>
 #include <aidl/android/hardware/automotive/vehicle/GetValueResult.h>
 #include <aidl/android/hardware/automotive/vehicle/GetValueResults.h>
+#include <aidl/android/hardware/automotive/vehicle/GsrComplianceRequirementType.h>
 #include <aidl/android/hardware/automotive/vehicle/Obd2CommonIgnitionMonitors.h>
 #include <aidl/android/hardware/automotive/vehicle/Obd2FuelSystemStatus.h>
 #include <aidl/android/hardware/automotive/vehicle/Obd2FuelType.h>
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h b/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
index ddc4f68..3d25cd3 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
@@ -46,6 +46,33 @@
     using ValueResultType = VhalResult<VehiclePropValuePool::RecyclableType>;
     using ValuesResultType = VhalResult<std::vector<VehiclePropValuePool::RecyclableType>>;
 
+    enum class EventMode : uint8_t {
+        /**
+         * Only invoke OnValueChangeCallback if the new property value (ignoring timestamp) is
+         * different than the existing value.
+         *
+         * This should be used for regular cases.
+         */
+        ON_VALUE_CHANGE,
+        /**
+         * Always invoke OnValueChangeCallback.
+         *
+         * This should be used for the special properties that are used for delivering event, e.g.
+         * HW_KEY_INPUT.
+         */
+        ALWAYS,
+        /**
+         * Never invoke OnValueChangeCallback.
+         *
+         * This should be used for continuous property subscription when the sample rate for the
+         * subscription is smaller than the refresh rate for the property. E.g., the vehicle speed
+         * is refreshed at 20hz, but we are only subscribing at 10hz. In this case, we want to
+         * generate the property change event at 10hz, not 20hz, but we still want to refresh the
+         * timestamp (via writeValue) at 20hz.
+         */
+        NEVER,
+    };
+
     explicit VehiclePropertyStore(std::shared_ptr<VehiclePropValuePool> valuePool)
         : mValuePool(valuePool) {}
 
@@ -72,8 +99,10 @@
     // 'status' would be initialized to {@code VehiclePropertyStatus::AVAILABLE}, if this is to
     // override an existing value, the status for the existing value would be used for the
     // overridden value.
+    // 'EventMode' controls whether the 'OnValueChangeCallback' will be called for this operation.
     VhalResult<void> writeValue(VehiclePropValuePool::RecyclableType propValue,
-                                bool updateStatus = false);
+                                bool updateStatus = false,
+                                EventMode mode = EventMode::ON_VALUE_CHANGE);
 
     // Remove a given property value from the property store. The 'propValue' would be used to
     // generate the key for the value to remove.
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
index c8fb994..646dc0e 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -106,7 +106,8 @@
 }
 
 VhalResult<void> VehiclePropertyStore::writeValue(VehiclePropValuePool::RecyclableType propValue,
-                                                  bool updateStatus) {
+                                                  bool updateStatus,
+                                                  VehiclePropertyStore::EventMode eventMode) {
     std::scoped_lock<std::mutex> g(mLock);
 
     int32_t propId = propValue->prop;
@@ -145,7 +146,12 @@
     }
 
     record->values[recId] = std::move(propValue);
-    if (valueUpdated && mOnValueChangeCallback != nullptr) {
+
+    if (eventMode == EventMode::NEVER) {
+        return {};
+    }
+
+    if ((eventMode == EventMode::ALWAYS || valueUpdated) && mOnValueChangeCallback != nullptr) {
         mOnValueChangeCallback(*(record->values[recId]));
     }
     return {};
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
index 4d6f811..fea5034 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
@@ -448,6 +448,67 @@
     ASSERT_EQ(updatedValue.prop, INVALID_PROP_ID);
 }
 
+TEST_F(VehiclePropertyStoreTest, testPropertyChangeCallbackNoUpdateForTimestampChange) {
+    VehiclePropValue updatedValue{
+            .prop = INVALID_PROP_ID,
+    };
+    VehiclePropValue fuelCapacity = {
+            .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+            .value = {.floatValues = {1.0}},
+    };
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+    mStore->setOnValueChangeCallback(
+            [&updatedValue](const VehiclePropValue& value) { updatedValue = value; });
+
+    // Write the same value with different timestamp should succeed but should not trigger callback.
+    fuelCapacity.timestamp = 1;
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+    ASSERT_EQ(updatedValue.prop, INVALID_PROP_ID);
+}
+
+TEST_F(VehiclePropertyStoreTest, testPropertyChangeCallbackForceUpdate) {
+    VehiclePropValue updatedValue{
+            .prop = INVALID_PROP_ID,
+    };
+    VehiclePropValue fuelCapacity = {
+            .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+            .value = {.floatValues = {1.0}},
+    };
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+    mStore->setOnValueChangeCallback(
+            [&updatedValue](const VehiclePropValue& value) { updatedValue = value; });
+
+    fuelCapacity.timestamp = 1;
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity), /*updateStatus=*/false,
+                                        VehiclePropertyStore::EventMode::ALWAYS));
+
+    ASSERT_EQ(updatedValue, fuelCapacity);
+}
+
+TEST_F(VehiclePropertyStoreTest, testPropertyChangeCallbackForceNoUpdate) {
+    VehiclePropValue updatedValue{
+            .prop = INVALID_PROP_ID,
+    };
+    VehiclePropValue fuelCapacity = {
+            .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+            .value = {.floatValues = {1.0}},
+    };
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+    mStore->setOnValueChangeCallback(
+            [&updatedValue](const VehiclePropValue& value) { updatedValue = value; });
+    fuelCapacity.value.floatValues[0] = 2.0;
+    fuelCapacity.timestamp = 1;
+
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity), /*updateStatus=*/false,
+                                        VehiclePropertyStore::EventMode::NEVER));
+
+    ASSERT_EQ(updatedValue.prop, INVALID_PROP_ID);
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/Android.bp b/automotive/vehicle/aidl/impl/vhal/Android.bp
index 5abcaf6..8b4f559 100644
--- a/automotive/vehicle/aidl/impl/vhal/Android.bp
+++ b/automotive/vehicle/aidl/impl/vhal/Android.bp
@@ -66,3 +66,36 @@
         "libbinder_ndk",
     ],
 }
+
+cc_fuzz {
+    name: "android.hardware.automotive.vehicle@V1-default-service_fuzzer",
+    vendor: true,
+    defaults: [
+        "FakeVehicleHardwareDefaults",
+        "VehicleHalDefaults",
+        "android-automotive-large-parcelable-defaults",
+    ],
+    header_libs: [
+        "IVehicleHardware",
+        "VehicleHalDefaultConfig",
+    ],
+    static_libs: [
+        "DefaultVehicleHal",
+        "FakeVehicleHardware",
+        "VehicleHalUtils",
+        "libbase",
+        "libbinder_random_parcel",
+        "libcutils",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libbinder",
+        "libutils",
+    ],
+    srcs: ["src/fuzzer.cpp"],
+    fuzz_config: {
+        cc: [
+            "keithmok@google.com",
+        ],
+    },
+}
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index b191aef..138aad5 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -355,6 +355,9 @@
         ALOGE("getValues: failed to parse getValues requests");
         return std::move(deserializedResults.error());
     }
+    if (callback == nullptr) {
+        return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+    }
     const std::vector<GetValueRequest>& getValueRequests =
             deserializedResults.value().getObject()->payloads;
 
@@ -438,6 +441,9 @@
         ALOGE("setValues: failed to parse setValues requests");
         return std::move(deserializedResults.error());
     }
+    if (callback == nullptr) {
+        return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+    }
     const std::vector<SetValueRequest>& setValueRequests =
             deserializedResults.value().getObject()->payloads;
 
@@ -629,7 +635,9 @@
         ALOGE("subscribe: invalid subscribe options: %s", getErrorMsg(result).c_str());
         return toScopedAStatus(result);
     }
-
+    if (callback == nullptr) {
+        return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+    }
     std::vector<SubscribeOptions> onChangeSubscriptions;
     std::vector<SubscribeOptions> continuousSubscriptions;
     for (const auto& option : options) {
@@ -685,6 +693,9 @@
 
 ScopedAStatus DefaultVehicleHal::unsubscribe(const CallbackType& callback,
                                              const std::vector<int32_t>& propIds) {
+    if (callback == nullptr) {
+        return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+    }
     return toScopedAStatus(mSubscriptionManager->unsubscribe(callback->asBinder().get(), propIds));
 }
 
diff --git a/automotive/vehicle/aidl/impl/vhal/src/fuzzer.cpp b/automotive/vehicle/aidl/impl/vhal/src/fuzzer.cpp
new file mode 100644
index 0000000..ac1e3b1
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/vhal/src/fuzzer.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <DefaultVehicleHal.h>
+#include <FakeVehicleHardware.h>
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+using ::android::fuzzService;
+using ::android::hardware::automotive::vehicle::DefaultVehicleHal;
+using ::android::hardware::automotive::vehicle::fake::FakeVehicleHardware;
+using ::ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    std::unique_ptr<FakeVehicleHardware> hardware = std::make_unique<FakeVehicleHardware>();
+    std::shared_ptr<DefaultVehicleHal> vhal =
+            ::ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
+
+    fuzzService(vhal->asBinder().get(), FuzzedDataProvider(data, size));
+
+    return 0;
+}
diff --git a/automotive/vehicle/vts/Android.bp b/automotive/vehicle/vts/Android.bp
index b78e0ff..1cfd542 100644
--- a/automotive/vehicle/vts/Android.bp
+++ b/automotive/vehicle/vts/Android.bp
@@ -44,6 +44,7 @@
     test_suites: [
         "general-tests",
         "vts",
+        "automotive-tests",
     ],
     require_root: true,
 }
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index c431d85..5de206b 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -48,6 +48,7 @@
 using ::android::getAidlHalInstanceNames;
 using ::android::base::ScopedLockAssertion;
 using ::android::base::StringPrintf;
+using ::android::frameworks::automotive::vhal::ErrorCode;
 using ::android::frameworks::automotive::vhal::HalPropError;
 using ::android::frameworks::automotive::vhal::IHalPropConfig;
 using ::android::frameworks::automotive::vhal::IHalPropValue;
@@ -287,7 +288,7 @@
     auto setValueResult = mVhalClient->setValueSync(*getValueResult.value());
 
     ASSERT_FALSE(setValueResult.ok()) << "Expect set a read-only value to fail";
-    ASSERT_EQ(setValueResult.error().code(), StatusCode::ACCESS_DENIED);
+    ASSERT_EQ(setValueResult.error().code(), ErrorCode::ACCESS_DENIED_FROM_VHAL);
 }
 
 // Test subscribe() and unsubscribe().
diff --git a/biometrics/common/thread/Android.bp b/biometrics/common/thread/Android.bp
new file mode 100644
index 0000000..a497d01
--- /dev/null
+++ b/biometrics/common/thread/Android.bp
@@ -0,0 +1,26 @@
+cc_library {
+    // 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
+    name: "android.hardware.biometrics.common.thread",
+    export_include_dirs: ["include"],
+    vendor: true,
+    srcs: [
+        "WorkerThread.cpp",
+    ],
+}
+
+cc_test_host {
+    name: "android.hardware.biometrics.common.WorkerThreadTest",
+    local_include_dirs: ["include"],
+    srcs: [
+        "tests/WorkerThreadTest.cpp",
+        "WorkerThread.cpp",
+    ],
+    shared_libs: [
+        "libcutils",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/biometrics/fingerprint/aidl/default/WorkerThread.cpp b/biometrics/common/thread/WorkerThread.cpp
similarity index 92%
rename from biometrics/fingerprint/aidl/default/WorkerThread.cpp
rename to biometrics/common/thread/WorkerThread.cpp
index 34ebb5c..61d1a13 100644
--- a/biometrics/fingerprint/aidl/default/WorkerThread.cpp
+++ b/biometrics/common/thread/WorkerThread.cpp
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#include "WorkerThread.h"
+#include "thread/WorkerThread.h"
 
-namespace aidl::android::hardware::biometrics::fingerprint {
+namespace aidl::android::hardware::biometrics {
 
 // It's important that mThread is initialized after everything else because it runs a member
 // function that may use any member of this class.
@@ -68,4 +68,4 @@
     }
 }
 
-}  // namespace aidl::android::hardware::biometrics::fingerprint
+}  // namespace aidl::android::hardware::biometrics
diff --git a/biometrics/fingerprint/aidl/default/include/Callable.h b/biometrics/common/thread/include/thread/Callable.h
similarity index 92%
rename from biometrics/fingerprint/aidl/default/include/Callable.h
rename to biometrics/common/thread/include/thread/Callable.h
index c629511..6eeff76 100644
--- a/biometrics/fingerprint/aidl/default/include/Callable.h
+++ b/biometrics/common/thread/include/thread/Callable.h
@@ -16,7 +16,7 @@
 
 #pragma once
 
-namespace aidl::android::hardware::biometrics::fingerprint {
+namespace aidl::android::hardware::biometrics {
 
 // Interface for representing parameterless functions. Unlike std::function<void()>, this can also
 // represent move-only lambdas.
@@ -51,4 +51,4 @@
     return std::make_unique<AnyFuncWrapper<T>>(std::move(func));
 }
 
-}  // namespace aidl::android::hardware::biometrics::fingerprint
\ No newline at end of file
+}  // namespace aidl::android::hardware::biometrics
\ No newline at end of file
diff --git a/biometrics/fingerprint/aidl/default/include/WorkerThread.h b/biometrics/common/thread/include/thread/WorkerThread.h
similarity index 95%
rename from biometrics/fingerprint/aidl/default/include/WorkerThread.h
rename to biometrics/common/thread/include/thread/WorkerThread.h
index 6fff4f2..5f89a7f 100644
--- a/biometrics/fingerprint/aidl/default/include/WorkerThread.h
+++ b/biometrics/common/thread/include/thread/WorkerThread.h
@@ -23,7 +23,7 @@
 
 #include "Callable.h"
 
-namespace aidl::android::hardware::biometrics::fingerprint {
+namespace aidl::android::hardware::biometrics {
 
 // A class that encapsulates a worker thread and a task queue, and provides a convenient interface
 // for a Session to schedule its tasks for asynchronous execution.
@@ -76,4 +76,4 @@
     std::thread mThread;
 };
 
-}  // namespace aidl::android::hardware::biometrics::fingerprint
+}  // namespace aidl::android::hardware::biometrics
diff --git a/biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp b/biometrics/common/thread/tests/WorkerThreadTest.cpp
similarity index 96%
rename from biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp
rename to biometrics/common/thread/tests/WorkerThreadTest.cpp
index 902fb40..5bb9e7e 100644
--- a/biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp
+++ b/biometrics/common/thread/tests/WorkerThreadTest.cpp
@@ -21,12 +21,11 @@
 
 #include <gtest/gtest.h>
 
-#include "WorkerThread.h"
+#include "thread/WorkerThread.h"
 
 namespace {
 
-using aidl::android::hardware::biometrics::fingerprint::Callable;
-using aidl::android::hardware::biometrics::fingerprint::WorkerThread;
+using namespace aidl::android::hardware::biometrics;
 using namespace std::chrono_literals;
 
 TEST(WorkerThreadTest, ScheduleReturnsTrueWhenQueueHasSpace) {
diff --git a/biometrics/common/util/Android.bp b/biometrics/common/util/Android.bp
new file mode 100644
index 0000000..918ef72
--- /dev/null
+++ b/biometrics/common/util/Android.bp
@@ -0,0 +1,18 @@
+cc_library {
+    // 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
+    name: "android.hardware.biometrics.common.util",
+    export_include_dirs: ["include"],
+    vendor: true,
+    srcs: [
+        "CancellationSignal.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "android.hardware.biometrics.common-V2-ndk",
+    ],
+}
diff --git a/biometrics/fingerprint/aidl/default/CancellationSignal.cpp b/biometrics/common/util/CancellationSignal.cpp
similarity index 87%
rename from biometrics/fingerprint/aidl/default/CancellationSignal.cpp
rename to biometrics/common/util/CancellationSignal.cpp
index 6598316..7888838 100644
--- a/biometrics/fingerprint/aidl/default/CancellationSignal.cpp
+++ b/biometrics/common/util/CancellationSignal.cpp
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-#include "CancellationSignal.h"
+#include "util/CancellationSignal.h"
 
 #include <android-base/logging.h>
 #include <chrono>
 
-namespace aidl::android::hardware::biometrics::fingerprint {
+namespace aidl::android::hardware::biometrics {
 
 CancellationSignal::CancellationSignal(std::promise<void>&& cancellationPromise)
     : mCancellationPromise(std::move(cancellationPromise)) {}
@@ -34,4 +34,4 @@
     return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
 }
 
-}  // namespace aidl::android::hardware::biometrics::fingerprint
+}  // namespace aidl::android::hardware::biometrics
diff --git a/biometrics/fingerprint/aidl/default/include/CancellationSignal.h b/biometrics/common/util/include/util/CancellationSignal.h
similarity index 83%
rename from biometrics/fingerprint/aidl/default/include/CancellationSignal.h
rename to biometrics/common/util/include/util/CancellationSignal.h
index 99f2fba..be77e29 100644
--- a/biometrics/fingerprint/aidl/default/include/CancellationSignal.h
+++ b/biometrics/common/util/include/util/CancellationSignal.h
@@ -17,13 +17,10 @@
 #pragma once
 
 #include <aidl/android/hardware/biometrics/common/BnCancellationSignal.h>
-#include <aidl/android/hardware/biometrics/fingerprint/ISessionCallback.h>
 #include <functional>
 #include <future>
 
-#include "WorkerThread.h"
-
-namespace aidl::android::hardware::biometrics::fingerprint {
+namespace aidl::android::hardware::biometrics {
 
 class CancellationSignal : public common::BnCancellationSignal {
   public:
@@ -39,4 +36,4 @@
 // to this future should be cancelled.
 bool shouldCancel(const std::future<void>& cancellationFuture);
 
-}  // namespace aidl::android::hardware::biometrics::fingerprint
+}  // namespace aidl::android::hardware::biometrics
diff --git a/biometrics/common/util/include/util/Util.h b/biometrics/common/util/include/util/Util.h
new file mode 100644
index 0000000..29ec0f8
--- /dev/null
+++ b/biometrics/common/util/include/util/Util.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+
+#include <chrono>
+#include <regex>
+#include <thread>
+#include <vector>
+
+namespace aidl::android::hardware::biometrics {
+
+#define SLEEP_MS(x) \
+    if (x > 0) std::this_thread::sleep_for(std::chrono::milliseconds(x))
+#define BEGIN_OP(x)            \
+    do {                       \
+        LOG(INFO) << __func__; \
+        SLEEP_MS(x);           \
+    } while (0)
+#define IS_TRUE(x) ((x == "1") || (x == "true"))
+
+// This is for non-test situations, such as casual cuttlefish users, that don't
+// set an explicit value.
+// Some operations (i.e. enroll, authenticate) will be executed in tight loops
+// by parts of the UI or fail if there is no latency. For example, the
+// Face settings page constantly runs auth and the enrollment UI uses a
+// cancel/restart cycle that requires some latency while the activities change.
+#define DEFAULT_LATENCY 800
+
+class Util {
+  public:
+    static int64_t getSystemNanoTime() {
+        timespec now;
+        clock_gettime(CLOCK_MONOTONIC, &now);
+        return now.tv_sec * 1000000000LL + now.tv_nsec;
+    }
+
+    static bool hasElapsed(int64_t start, int64_t durationMillis) {
+        auto now = getSystemNanoTime();
+        if (now < start) return true;
+        if (durationMillis <= 0) return true;
+        return ((now - start) / 1000000LL) > durationMillis;
+    }
+
+    static std::vector<std::string> split(const std::string& str, const std::string& sep) {
+        std::regex regex(sep);
+        std::vector<std::string> parts(
+                std::sregex_token_iterator(str.begin(), str.end(), regex, -1),
+                std::sregex_token_iterator());
+        return parts;
+    }
+};
+
+}  // namespace aidl::android::hardware::biometrics
\ No newline at end of file
diff --git a/biometrics/face/aidl/default/Android.bp b/biometrics/face/aidl/default/Android.bp
index 7f66eca..63a3645 100644
--- a/biometrics/face/aidl/default/Android.bp
+++ b/biometrics/face/aidl/default/Android.bp
@@ -18,10 +18,43 @@
         "libbinder_ndk",
         "android.hardware.biometrics.face-V2-ndk",
         "android.hardware.biometrics.common-V2-ndk",
+        "android.hardware.biometrics.common.thread",
+        "android.hardware.biometrics.common.util",
     ],
     srcs: [
         "main.cpp",
         "Face.cpp",
+        "FakeFaceEngine.cpp",
         "Session.cpp",
     ],
+    static_libs: ["libandroid.hardware.biometrics.face.VirtualProps"],
+}
+
+sysprop_library {
+    name: "android.hardware.biometrics.face.VirtualProps",
+    srcs: ["face.sysprop"],
+    property_owner: "Vendor",
+    vendor: true,
+}
+
+cc_test {
+    name: "android.hardware.biometrics.face.FakeFaceEngineTest",
+    srcs: [
+        "tests/FakeFaceEngineTest.cpp",
+        "FakeFaceEngine.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "libandroid.hardware.biometrics.face.VirtualProps",
+        "android.hardware.biometrics.face-V2-ndk",
+        "android.hardware.biometrics.common-V2-ndk",
+        "android.hardware.keymaster-V3-ndk",
+        "android.hardware.biometrics.common.util",
+    ],
+    vendor: true,
+    test_suites: ["general-tests"],
+    require_root: true,
 }
diff --git a/biometrics/face/aidl/default/Face.cpp b/biometrics/face/aidl/default/Face.cpp
index aca3e13..652a7e1 100644
--- a/biometrics/face/aidl/default/Face.cpp
+++ b/biometrics/face/aidl/default/Face.cpp
@@ -17,12 +17,14 @@
 #include "Face.h"
 #include "Session.h"
 
+#include "FakeFaceEngine.h"
+
 namespace aidl::android::hardware::biometrics::face {
 
 const int kSensorId = 4;
-const common::SensorStrength kSensorStrength = common::SensorStrength::STRONG;
+const common::SensorStrength kSensorStrength = FakeFaceEngine::GetSensorStrength();
 const int kMaxEnrollmentsPerUser = 5;
-const FaceSensorType kSensorType = FaceSensorType::RGB;
+const FaceSensorType kSensorType = FakeFaceEngine::GetSensorType();
 const bool kHalControlsPreview = true;
 const std::string kHwComponentId = "faceSensor";
 const std::string kHardwareVersion = "vendor/model/revision";
@@ -69,7 +71,7 @@
 ndk::ScopedAStatus Face::createSession(int32_t /*sensorId*/, int32_t /*userId*/,
                                        const std::shared_ptr<ISessionCallback>& cb,
                                        std::shared_ptr<ISession>* return_val) {
-    *return_val = SharedRefBase::make<Session>(cb);
+    *return_val = SharedRefBase::make<Session>(std::make_unique<FakeFaceEngine>(), cb);
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/biometrics/face/aidl/default/FakeFaceEngine.cpp b/biometrics/face/aidl/default/FakeFaceEngine.cpp
new file mode 100644
index 0000000..0f088f4
--- /dev/null
+++ b/biometrics/face/aidl/default/FakeFaceEngine.cpp
@@ -0,0 +1,318 @@
+#include "FakeFaceEngine.h"
+
+#include <android-base/logging.h>
+
+#include <face.sysprop.h>
+
+#include "util/CancellationSignal.h"
+#include "util/Util.h"
+
+using namespace ::android::face::virt;
+
+namespace aidl::android::hardware::biometrics::face {
+
+FaceSensorType FakeFaceEngine::GetSensorType() {
+    std::string type = FaceHalProperties::type().value_or("");
+    if (type == "IR") {
+        return FaceSensorType::IR;
+    } else {
+        FaceHalProperties::type("RGB");
+        return FaceSensorType::RGB;
+    }
+}
+
+common::SensorStrength FakeFaceEngine::GetSensorStrength() {
+    std::string strength = FaceHalProperties::strength().value_or("");
+    if (strength == "convenience") {
+        return common::SensorStrength::CONVENIENCE;
+    } else if (strength == "weak") {
+        return common::SensorStrength::WEAK;
+    } else {
+        FaceHalProperties::strength("strong");
+        return common::SensorStrength::STRONG;
+    }
+}
+
+void FakeFaceEngine::generateChallengeImpl(ISessionCallback* cb) {
+    BEGIN_OP(0);
+    std::uniform_int_distribution<int64_t> dist;
+    auto challenge = dist(mRandom);
+    FaceHalProperties::challenge(challenge);
+    cb->onChallengeGenerated(challenge);
+}
+
+void FakeFaceEngine::revokeChallengeImpl(ISessionCallback* cb, int64_t challenge) {
+    BEGIN_OP(0);
+    FaceHalProperties::challenge({});
+    cb->onChallengeRevoked(challenge);
+}
+void FakeFaceEngine::getEnrollmentConfigImpl(ISessionCallback* /*cb*/,
+                                             std::vector<EnrollmentStageConfig>* /*return_val*/) {}
+void FakeFaceEngine::enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
+                                EnrollmentType /*enrollmentType*/,
+                                const std::vector<Feature>& /*features*/,
+                                const std::future<void>& cancel) {
+    BEGIN_OP(FaceHalProperties::operation_start_enroll_latency().value_or(0));
+    // format is "<id>,<bucket_id>:<delay>:<succeeds>,<bucket_id>:<delay>:<succeeds>...
+    auto nextEnroll = FaceHalProperties::next_enrollment().value_or("");
+    // Erase the next enrollment
+    FaceHalProperties::next_enrollment({});
+
+    AuthenticationFrame frame;
+    frame.data.acquiredInfo = AcquiredInfo::START;
+    frame.data.vendorCode = 0;
+    cb->onAuthenticationFrame(frame);
+
+    // Do proper HAT verification in the real implementation.
+    if (hat.mac.empty()) {
+        LOG(ERROR) << "Fail: hat";
+        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
+        return;
+    }
+
+    if (FaceHalProperties::operation_enroll_fails().value_or(false)) {
+        LOG(ERROR) << "Fail: operation_enroll_fails";
+        cb->onError(Error::VENDOR, 0 /* vendorError */);
+        return;
+    }
+
+    auto parts = Util::split(nextEnroll, ",");
+    if (parts.size() < 2) {
+        LOG(ERROR) << "Fail: invalid next_enrollment for : " << nextEnroll;
+        cb->onError(Error::VENDOR, 0 /* vendorError */);
+        return;
+    }
+
+    auto enrollmentId = std::stoi(parts[0]);
+    const int numBuckets = parts.size() - 1;
+    for (size_t i = 1; i < parts.size(); i++) {
+        auto enrollHit = Util::split(parts[i], ":");
+        if (enrollHit.size() != 3) {
+            LOG(ERROR) << "Error when unpacking enrollment hit: " << parts[i];
+            cb->onError(Error::VENDOR, 0 /* vendorError */);
+        }
+        std::string bucket = enrollHit[0];
+        std::string delay = enrollHit[1];
+        std::string succeeds = enrollHit[2];
+
+        SLEEP_MS(std::stoi(delay));
+
+        if (shouldCancel(cancel)) {
+            LOG(ERROR) << "Fail: cancel";
+            cb->onError(Error::CANCELED, 0 /* vendorCode */);
+            return;
+        }
+
+        if (!IS_TRUE(succeeds)) {  // end and failed
+            LOG(ERROR) << "Fail: requested by caller: " << parts[i];
+            cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+            return;
+        }
+
+        EnrollmentFrame frame;
+
+        frame.data.acquiredInfo = AcquiredInfo::GOOD;
+        frame.data.vendorCode = 0;
+        cb->onEnrollmentFrame(frame);
+
+        frame.data.acquiredInfo = AcquiredInfo::VENDOR;
+        frame.data.vendorCode = std::stoi(bucket);
+        cb->onEnrollmentFrame(frame);
+
+        int remainingBuckets = numBuckets - i;
+        if (remainingBuckets > 0) {
+            cb->onEnrollmentProgress(enrollmentId, remainingBuckets);
+        }
+    }
+
+    auto enrollments = FaceHalProperties::enrollments();
+    enrollments.push_back(enrollmentId);
+    FaceHalProperties::enrollments(enrollments);
+    LOG(INFO) << "enrolled : " << enrollmentId;
+    cb->onEnrollmentProgress(enrollmentId, 0);
+}
+
+void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationId*/,
+                                      const std::future<void>& cancel) {
+    BEGIN_OP(FaceHalProperties::operation_authenticate_latency().value_or(0));
+
+    // Signal to the framework that we have begun authenticating.
+    AuthenticationFrame frame;
+    frame.data.acquiredInfo = AcquiredInfo::START;
+    frame.data.vendorCode = 0;
+    cb->onAuthenticationFrame(frame);
+
+    // Also signal that we have opened the camera.
+    frame = {};
+    frame.data.acquiredInfo = AcquiredInfo::FIRST_FRAME_RECEIVED;
+    frame.data.vendorCode = 0;
+    cb->onAuthenticationFrame(frame);
+
+    auto now = Util::getSystemNanoTime();
+    int64_t duration = FaceHalProperties::operation_authenticate_duration().value_or(0);
+    if (duration > 0) {
+        do {
+            SLEEP_MS(5);
+        } while (!Util::hasElapsed(now, duration));
+    }
+
+    if (FaceHalProperties::operation_authenticate_fails().value_or(false)) {
+        LOG(ERROR) << "Fail: operation_authenticate_fails";
+        cb->onError(Error::VENDOR, 0 /* vendorError */);
+        return;
+    }
+
+    if (FaceHalProperties::lockout().value_or(false)) {
+        LOG(ERROR) << "Fail: lockout";
+        cb->onLockoutPermanent();
+        cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
+        return;
+    }
+
+    if (shouldCancel(cancel)) {
+        LOG(ERROR) << "Fail: cancel";
+        cb->onError(Error::CANCELED, 0 /* vendorCode */);
+        return;
+    }
+
+    auto id = FaceHalProperties::enrollment_hit().value_or(0);
+    auto enrolls = FaceHalProperties::enrollments();
+    auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
+    if (id < 0 || !isEnrolled) {
+        LOG(ERROR) << (isEnrolled ? "invalid enrollment hit" : "Fail: not enrolled");
+        cb->onAuthenticationFailed();
+        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
+        return;
+    }
+
+    cb->onAuthenticationSucceeded(id, {} /* hat */);
+}
+
+void FakeFaceEngine::detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel) {
+    BEGIN_OP(FaceHalProperties::operation_detect_interaction_latency().value_or(0));
+
+    if (FaceHalProperties::operation_detect_interaction_fails().value_or(false)) {
+        LOG(ERROR) << "Fail: operation_detect_interaction_fails";
+        cb->onError(Error::VENDOR, 0 /* vendorError */);
+        return;
+    }
+
+    if (shouldCancel(cancel)) {
+        LOG(ERROR) << "Fail: cancel";
+        cb->onError(Error::CANCELED, 0 /* vendorCode */);
+        return;
+    }
+
+    auto id = FaceHalProperties::enrollment_hit().value_or(0);
+    auto enrolls = FaceHalProperties::enrollments();
+    auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
+    if (id <= 0 || !isEnrolled) {
+        LOG(ERROR) << "Fail: not enrolled";
+        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
+        return;
+    }
+
+    cb->onInteractionDetected();
+}
+
+void FakeFaceEngine::enumerateEnrollmentsImpl(ISessionCallback* cb) {
+    BEGIN_OP(0);
+    std::vector<int32_t> enrollments;
+    for (const auto& enrollmentId : FaceHalProperties::enrollments()) {
+        if (enrollmentId) {
+            enrollments.push_back(*enrollmentId);
+        }
+    }
+    cb->onEnrollmentsEnumerated(enrollments);
+}
+
+void FakeFaceEngine::removeEnrollmentsImpl(ISessionCallback* cb,
+                                           const std::vector<int32_t>& enrollmentIds) {
+    BEGIN_OP(0);
+
+    std::vector<std::optional<int32_t>> newEnrollments;
+    for (const auto& enrollment : FaceHalProperties::enrollments()) {
+        auto id = enrollment.value_or(0);
+        if (std::find(enrollmentIds.begin(), enrollmentIds.end(), id) == enrollmentIds.end()) {
+            newEnrollments.emplace_back(id);
+        }
+    }
+    FaceHalProperties::enrollments(newEnrollments);
+    cb->onEnrollmentsRemoved(enrollmentIds);
+}
+
+void FakeFaceEngine::getFeaturesImpl(ISessionCallback* cb) {
+    BEGIN_OP(0);
+
+    if (FaceHalProperties::enrollments().empty()) {
+        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+        return;
+    }
+
+    std::vector<Feature> featuresToReturn = {};
+    for (const auto& feature : FaceHalProperties::features()) {
+        if (feature) {
+            featuresToReturn.push_back((Feature)(*feature));
+        }
+    }
+    cb->onFeaturesRetrieved(featuresToReturn);
+}
+
+void FakeFaceEngine::setFeatureImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
+                                    Feature feature, bool enabled) {
+    BEGIN_OP(0);
+
+    if (FaceHalProperties::enrollments().empty()) {
+        LOG(ERROR) << "Unable to set feature, enrollments are empty";
+        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+        return;
+    }
+
+    if (hat.mac.empty()) {
+        LOG(ERROR) << "Unable to set feature, invalid hat";
+        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+        return;
+    }
+
+    auto features = FaceHalProperties::features();
+
+    auto itr = std::find_if(features.begin(), features.end(), [feature](const auto& theFeature) {
+        return *theFeature == (int)feature;
+    });
+
+    if (!enabled && (itr != features.end())) {
+        features.erase(itr);
+    } else if (enabled && (itr == features.end())) {
+        features.push_back((int)feature);
+    }
+
+    FaceHalProperties::features(features);
+    cb->onFeatureSet(feature);
+}
+
+void FakeFaceEngine::getAuthenticatorIdImpl(ISessionCallback* cb) {
+    BEGIN_OP(0);
+    // If this is a weak HAL return 0 per the spec.
+    if (GetSensorStrength() != common::SensorStrength::STRONG) {
+        cb->onAuthenticatorIdRetrieved(0);
+    } else {
+        cb->onAuthenticatorIdRetrieved(FaceHalProperties::authenticator_id().value_or(0));
+    }
+}
+
+void FakeFaceEngine::invalidateAuthenticatorIdImpl(ISessionCallback* cb) {
+    BEGIN_OP(0);
+    int64_t authenticatorId = FaceHalProperties::authenticator_id().value_or(0);
+    int64_t newId = authenticatorId + 1;
+    FaceHalProperties::authenticator_id(newId);
+    cb->onAuthenticatorIdInvalidated(newId);
+}
+
+void FakeFaceEngine::resetLockoutImpl(ISessionCallback* cb,
+                                      const keymaster::HardwareAuthToken& /*hat*/) {
+    BEGIN_OP(0);
+    FaceHalProperties::lockout(false);
+    cb->onLockoutCleared();
+}
+
+}  // namespace aidl::android::hardware::biometrics::face
\ No newline at end of file
diff --git a/biometrics/face/aidl/default/FakeFaceEngine.h b/biometrics/face/aidl/default/FakeFaceEngine.h
new file mode 100644
index 0000000..edb54ce
--- /dev/null
+++ b/biometrics/face/aidl/default/FakeFaceEngine.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/biometrics/common/SensorStrength.h>
+#include <aidl/android/hardware/biometrics/face/BnSession.h>
+#include <aidl/android/hardware/biometrics/face/FaceSensorType.h>
+#include <aidl/android/hardware/biometrics/face/ISessionCallback.h>
+
+#include <random>
+
+#include <future>
+#include <vector>
+
+namespace aidl::android::hardware::biometrics::face {
+
+namespace face = aidl::android::hardware::biometrics::face;
+namespace common = aidl::android::hardware::biometrics::common;
+namespace keymaster = aidl::android::hardware::keymaster;
+
+using aidl::android::hardware::common::NativeHandle;
+// A fake engine that is backed by system properties instead of hardware.
+class FakeFaceEngine {
+  public:
+    FakeFaceEngine() : mRandom(std::mt19937::default_seed) {}
+
+    static face::FaceSensorType GetSensorType();
+    static common::SensorStrength GetSensorStrength();
+    void generateChallengeImpl(ISessionCallback* cb);
+    void revokeChallengeImpl(ISessionCallback* cb, int64_t challenge);
+    void getEnrollmentConfigImpl(ISessionCallback* cb,
+                                 std::vector<EnrollmentStageConfig>* return_val);
+    void enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
+                    EnrollmentType enrollmentType, const std::vector<Feature>& features,
+                    const std::future<void>& cancel);
+    void authenticateImpl(ISessionCallback* cb, int64_t operationId,
+                          const std::future<void>& cancel);
+    void detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel);
+    void enumerateEnrollmentsImpl(ISessionCallback* cb);
+    void removeEnrollmentsImpl(ISessionCallback* cb, const std::vector<int32_t>& enrollmentIds);
+    void getFeaturesImpl(ISessionCallback* cb);
+    void setFeatureImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
+                        Feature feature, bool enabled);
+    void getAuthenticatorIdImpl(ISessionCallback* cb);
+    void invalidateAuthenticatorIdImpl(ISessionCallback* cb);
+    void resetLockoutImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& /*hat*/);
+
+    std::mt19937 mRandom;
+};
+
+}  // namespace aidl::android::hardware::biometrics::face
\ No newline at end of file
diff --git a/biometrics/face/aidl/default/README.md b/biometrics/face/aidl/default/README.md
new file mode 100644
index 0000000..1655973
--- /dev/null
+++ b/biometrics/face/aidl/default/README.md
@@ -0,0 +1,77 @@
+# Virtual Face HAL
+
+This is a virtual HAL implementation that is backed by system properties
+instead of actual hardware. It's intended for testing and UI development
+on debuggable builds to allow devices to masquerade as alternative device
+types and for emulators.
+
+## Device Selection
+
+You can either run the FakeFaceEngine on a [real device](#actual-device) or a [virtual device/cuttlefish](#getting-started-on-a-virtual-device-cuttlefish). This document should
+help you to get started on either one.
+
+After setting up a device, go ahead and try out [enrolling](#enrolling) & [authenticating](#authenticating)
+
+### Getting started on a Virtual Device (cuttlefish)
+
+
+Note, I'm running this via a cloudtop virtual device.
+
+1. Setup cuttlefish on cloudtop, See [this](https://g3doc.corp.google.com/company/teams/android/teampages/acloud/getting_started.md?cl=head) for more details.
+2. acloud create --local-image
+3. Enter in the shell command to disable hidl
+
+```shell
+$ adb root
+$ adb shell settings put secure com.android.server.biometrics.AuthService.hidlDisabled 1
+$ adb reboot
+```
+4. You should now be able to do fake enrollments and authentications (as seen down below)
+
+### Actual Device
+
+1. Modify your real devices make file (I.E. vendor/google/products/{YOUR_DEVICE}.mk)
+2. Ensure that there is no other face HAL that is being included by the device
+3. Add the following
+```
+PRODUCT_COPY_FILES += \
+    frameworks/native/data/etc/android.hardware.biometrics.face.xml:$(TARGET_COPY_OUT_PRODUCT)/etc/permissions/android.hardware.biometrics.face.xml
+
+PRODUCT_PACKAGES += \
+    android.hardware.biometrics.face-service.example \
+
+```
+4. Now build and flash m -j120 && flash
+5. Run the following commands
+
+```shell
+# This is a temporary workaround
+$ adb root
+$ adb shell setprop persist.vendor.face.virtual.type RGB
+$ adb shell setprop persist.vendor.face.virtual.strength strong
+$ adb shell locksettings set-pin 0000
+$ adb reboot
+```
+
+## Enrolling
+
+```shell
+# authenticar_id,bucket_id:duration:(true|false)....
+$ adb shell setprop vendor.face.virtual.next_enrollment 1,0:500:true,5:250:true,10:150:true,15:500:true
+$ adb shell am start -n com.android.settings/.biometrics.face.FaceEnrollIntroduction
+# If you would like to get rid of the enrollment, run the follwoing command
+$ adb shell setprop persist.vendor.face.virtual.enrollments \"\"
+```
+
+## Authenticating
+
+```shell
+# If enrollment hasn't been setup
+$ adb shell setprop persist.vendor.face.virtual.enrollments 1
+$ adb shell cmd face sync
+# After enrollment has been setup
+$ adb shell setprop vendor.face.virtual.operation_authenticate_duration 800
+$ adb shell setprop vendor.face.virtual.enrollment_hit 1
+# Power button press to simulate auth
+$ adb shell input keyevent 26
+```
diff --git a/biometrics/face/aidl/default/Session.cpp b/biometrics/face/aidl/default/Session.cpp
index 984a1a9..1188459 100644
--- a/biometrics/face/aidl/default/Session.cpp
+++ b/biometrics/face/aidl/default/Session.cpp
@@ -14,139 +14,135 @@
  * limitations under the License.
  */
 
-#include <aidl/android/hardware/biometrics/common/BnCancellationSignal.h>
 #include <android-base/logging.h>
 
 #include "Session.h"
 
 namespace aidl::android::hardware::biometrics::face {
 
-class CancellationSignal : public common::BnCancellationSignal {
-  private:
-    std::shared_ptr<ISessionCallback> cb_;
+constexpr size_t MAX_WORKER_QUEUE_SIZE = 5;
 
-  public:
-    explicit CancellationSignal(std::shared_ptr<ISessionCallback> cb) : cb_(std::move(cb)) {}
-
-    ndk::ScopedAStatus cancel() override {
-        cb_->onError(Error::CANCELED, 0 /* vendorCode */);
-        return ndk::ScopedAStatus::ok();
-    }
-};
-
-Session::Session(std::shared_ptr<ISessionCallback> cb)
-    : cb_(std::move(cb)), mRandom(std::mt19937::default_seed) {}
+Session::Session(std::unique_ptr<FakeFaceEngine> engine, std::shared_ptr<ISessionCallback> cb)
+    : mEngine(std::move(engine)), mCb(std::move(cb)), mRandom(std::mt19937::default_seed) {
+    mThread = std::make_unique<WorkerThread>(MAX_WORKER_QUEUE_SIZE);
+}
 
 ndk::ScopedAStatus Session::generateChallenge() {
     LOG(INFO) << "generateChallenge";
-    if (cb_) {
-        std::uniform_int_distribution<int64_t> dist;
-        auto challenge = dist(mRandom);
-        cb_->onChallengeGenerated(challenge);
-    }
+    mThread->schedule(Callable::from([this] { mEngine->generateChallengeImpl(mCb.get()); }));
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::revokeChallenge(int64_t challenge) {
     LOG(INFO) << "revokeChallenge";
-    if (cb_) {
-        cb_->onChallengeRevoked(challenge);
-    }
+    mThread->schedule(Callable::from(
+            [this, challenge] { mEngine->revokeChallengeImpl(mCb.get(), challenge); }));
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::getEnrollmentConfig(EnrollmentType /*enrollmentType*/,
-                                                std::vector<EnrollmentStageConfig>* return_val) {
-    *return_val = {};
+ndk::ScopedAStatus Session::getEnrollmentConfig(
+        EnrollmentType /*enrollmentType*/, std::vector<EnrollmentStageConfig>* cancellationSignal) {
+    *cancellationSignal = {};
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::enroll(
-        const keymaster::HardwareAuthToken& /*hat*/, EnrollmentType /*enrollmentType*/,
-        const std::vector<Feature>& /*features*/,
-        const std::optional<NativeHandle>& /*previewSurface*/,
-        std::shared_ptr<biometrics::common::ICancellationSignal>* /*return_val*/) {
+        const keymaster::HardwareAuthToken& hat, EnrollmentType enrollmentType,
+        const std::vector<Feature>& features, const std::optional<NativeHandle>& /*previewSurface*/,
+        std::shared_ptr<biometrics::common::ICancellationSignal>* cancellationSignal) {
     LOG(INFO) << "enroll";
-    if (cb_) {
-        cb_->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
-    }
+    std::promise<void> cancellationPromise;
+    auto cancFuture = cancellationPromise.get_future();
+
+    mThread->schedule(Callable::from(
+            [this, hat, enrollmentType, features, cancFuture = std::move(cancFuture)] {
+                mEngine->enrollImpl(mCb.get(), hat, enrollmentType, features, cancFuture);
+            }));
+
+    *cancellationSignal = SharedRefBase::make<CancellationSignal>(std::move(cancellationPromise));
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::authenticate(int64_t /*keystoreOperationId*/,
-                                         std::shared_ptr<common::ICancellationSignal>* return_val) {
+ndk::ScopedAStatus Session::authenticate(
+        int64_t keystoreOperationId,
+        std::shared_ptr<common::ICancellationSignal>* cancellationSignal) {
     LOG(INFO) << "authenticate";
-    if (cb_) {
-        cb_->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
-    }
-    *return_val = SharedRefBase::make<CancellationSignal>(cb_);
+    std::promise<void> cancellationPromise;
+    auto cancFuture = cancellationPromise.get_future();
+
+    mThread->schedule(
+            Callable::from([this, keystoreOperationId, cancFuture = std::move(cancFuture)] {
+                mEngine->authenticateImpl(mCb.get(), keystoreOperationId, cancFuture);
+            }));
+
+    *cancellationSignal = SharedRefBase::make<CancellationSignal>(std::move(cancellationPromise));
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::detectInteraction(
-        std::shared_ptr<common::ICancellationSignal>* /*return_val*/) {
+        std::shared_ptr<common::ICancellationSignal>* cancellationSignal) {
     LOG(INFO) << "detectInteraction";
+    std::promise<void> cancellationPromise;
+    auto cancFuture = cancellationPromise.get_future();
+
+    mThread->schedule(Callable::from([this, cancFuture = std::move(cancFuture)] {
+        mEngine->detectInteractionImpl(mCb.get(), cancFuture);
+    }));
+
+    *cancellationSignal = SharedRefBase::make<CancellationSignal>(std::move(cancellationPromise));
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::enumerateEnrollments() {
     LOG(INFO) << "enumerateEnrollments";
-    if (cb_) {
-        cb_->onEnrollmentsEnumerated(std::vector<int32_t>());
-    }
+    mThread->schedule(Callable::from([this] { mEngine->enumerateEnrollmentsImpl(mCb.get()); }));
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::removeEnrollments(const std::vector<int32_t>& /*enrollmentIds*/) {
+ndk::ScopedAStatus Session::removeEnrollments(const std::vector<int32_t>& enrollmentIds) {
     LOG(INFO) << "removeEnrollments";
-    if (cb_) {
-        cb_->onEnrollmentsRemoved(std::vector<int32_t>());
-    }
+    mThread->schedule(Callable::from(
+            [this, enrollmentIds] { mEngine->removeEnrollmentsImpl(mCb.get(), enrollmentIds); }));
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::getFeatures() {
     LOG(INFO) << "getFeatures";
-    if (cb_) {
-        // Must error out with UNABLE_TO_PROCESS when no faces are enrolled.
-        cb_->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
-    }
+    mThread->schedule(Callable::from([this] { mEngine->getFeaturesImpl(mCb.get()); }));
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::setFeature(const keymaster::HardwareAuthToken& /*hat*/,
-                                       Feature /*feature*/, bool /*enabled*/) {
+ndk::ScopedAStatus Session::setFeature(const keymaster::HardwareAuthToken& hat, Feature feature,
+                                       bool enabled) {
     LOG(INFO) << "setFeature";
+    mThread->schedule(Callable::from([this, hat, feature, enabled] {
+        mEngine->setFeatureImpl(mCb.get(), hat, feature, enabled);
+    }));
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::getAuthenticatorId() {
     LOG(INFO) << "getAuthenticatorId";
-    if (cb_) {
-        cb_->onAuthenticatorIdRetrieved(0 /* authenticatorId */);
-    }
+    mThread->schedule(Callable::from([this] { mEngine->getAuthenticatorIdImpl(mCb.get()); }));
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::invalidateAuthenticatorId() {
     LOG(INFO) << "invalidateAuthenticatorId";
-    if (cb_) {
-        cb_->onAuthenticatorIdInvalidated(0);
-    }
+    mThread->schedule(
+            Callable::from([this] { mEngine->invalidateAuthenticatorIdImpl(mCb.get()); }));
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::resetLockout(const keymaster::HardwareAuthToken& /*hat*/) {
+ndk::ScopedAStatus Session::resetLockout(const keymaster::HardwareAuthToken& hat) {
     LOG(INFO) << "resetLockout";
-    if (cb_) {
-        cb_->onLockoutCleared();
-    }
+    mThread->schedule(Callable::from([this, hat] { mEngine->resetLockoutImpl(mCb.get(), hat); }));
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::close() {
-    if (cb_) {
-        cb_->onSessionClosed();
+    if (mCb) {
+        mCb->onSessionClosed();
     }
     return ndk::ScopedAStatus::ok();
 }
diff --git a/biometrics/face/aidl/default/Session.h b/biometrics/face/aidl/default/Session.h
index 9db17d2..7ca6a1f 100644
--- a/biometrics/face/aidl/default/Session.h
+++ b/biometrics/face/aidl/default/Session.h
@@ -21,6 +21,10 @@
 #include <aidl/android/hardware/biometrics/face/BnSession.h>
 #include <aidl/android/hardware/biometrics/face/ISessionCallback.h>
 
+#include "FakeFaceEngine.h"
+#include "thread/WorkerThread.h"
+#include "util/CancellationSignal.h"
+
 namespace aidl::android::hardware::biometrics::face {
 
 namespace common = aidl::android::hardware::biometrics::common;
@@ -30,7 +34,7 @@
 
 class Session : public BnSession {
   public:
-    explicit Session(std::shared_ptr<ISessionCallback> cb);
+    explicit Session(std::unique_ptr<FakeFaceEngine> engine, std::shared_ptr<ISessionCallback> cb);
 
     ndk::ScopedAStatus generateChallenge() override;
 
@@ -85,8 +89,11 @@
     ndk::ScopedAStatus onContextChanged(const common::OperationContext& context) override;
 
   private:
-    std::shared_ptr<ISessionCallback> cb_;
+    std::unique_ptr<FakeFaceEngine> mEngine;
+    std::shared_ptr<ISessionCallback> mCb;
     std::mt19937 mRandom;
+    std::unique_ptr<WorkerThread> mThread;
+    std::shared_ptr<CancellationSignal> mCancellationSignal;
 };
 
 }  // namespace aidl::android::hardware::biometrics::face
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
new file mode 100644
index 0000000..9548920
--- /dev/null
+++ b/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
@@ -0,0 +1,98 @@
+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: "next_enrollment"
+    type: String
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.next_enrollment"
+  }
+  prop {
+    api_name: "operation_authenticate_duration"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_authenticate_duration"
+  }
+  prop {
+    api_name: "operation_authenticate_fails"
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_authenticate_fails"
+  }
+  prop {
+    api_name: "operation_authenticate_latency"
+    type: Integer
+    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: Integer
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_detect_interaction_latency"
+  }
+  prop {
+    api_name: "operation_enroll_fails"
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_enroll_fails"
+  }
+  prop {
+    api_name: "operation_start_enroll_latency"
+    type: Integer
+    access: ReadWrite
+    prop_name: "vendor.face.virtual.operation_start_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.sysprop b/biometrics/face/aidl/default/face.sysprop
new file mode 100644
index 0000000..6b0f37f
--- /dev/null
+++ b/biometrics/face/aidl/default/face.sysprop
@@ -0,0 +1,159 @@
+# face.sysprop
+# module becomes static class (Java) / namespace (C++) for serving API
+module: "android.face.virt.FaceHalProperties"
+owner: Vendor
+
+# type of face sensor
+prop {
+    prop_name: "persist.vendor.face.virtual.type"
+    type: String
+    scope: Public
+    access: ReadWrite
+    enum_values: "IR|RGB"
+    api_name: "type"
+}
+
+# the strength of the sensor
+prop {
+    prop_name: "persist.vendor.face.virtual.strength"
+    type: String
+    scope: Public
+    access: ReadWrite
+    enum_values: "convenience|weak|strong"
+    api_name: "strength"
+}
+
+# ids of current enrollments
+prop {
+    prop_name: "persist.vendor.face.virtual.enrollments"
+    type: IntegerList
+    scope: Public
+    access: ReadWrite
+    api_name: "enrollments"
+}
+
+# List of features
+prop {
+    prop_name: "persist.vendor.face.virtual.features"
+    type: IntegerList
+    scope: Public
+    access: ReadWrite
+    api_name: "features"
+}
+
+# authenticate and detectInteraction will succeed with this
+# enrollment id, when present, otherwise they will error
+prop {
+    prop_name: "vendor.face.virtual.enrollment_hit"
+    type: Integer
+    scope: Public
+    access: ReadWrite
+    api_name: "enrollment_hit"
+}
+
+# The initial latency for enrollment
+prop {
+    prop_name: "vendor.face.virtual.operation_start_enroll_latency"
+    type: Integer
+    scope: Public
+    access: ReadWrite
+    api_name: "operation_start_enroll_latency"
+}
+
+# the next enrollment in the format:
+# "<id>,<bucket_id>:<delay>:<succeeds>,<bucket_id>..."
+# for example: "0:1,0:100:1,1:200:1" indicating that bucket 0 took
+# 50 milliseconds, bucket 1 took 100 milliseconds, bucket 2 took 200 milliseconds.
+# Note that it is up to the configuration to determine how many buckets are required
+# to complete an enrollment
+prop {
+    prop_name: "vendor.face.virtual.next_enrollment"
+    type: String
+    scope: Public
+    access: ReadWrite
+    api_name: "next_enrollment"
+}
+
+# value for getAuthenticatorId or 0
+prop {
+    prop_name: "vendor.face.virtual.authenticator_id"
+    type: Long
+    scope: Public
+    access: ReadWrite
+    api_name: "authenticator_id"
+}
+
+# value for generateChallenge
+prop {
+    prop_name: "vendor.face.virtual.challenge"
+    type: Long
+    scope: Public
+    access: ReadWrite
+    api_name: "challenge"
+}
+
+# if locked out
+prop {
+    prop_name: "vendor.face.virtual.lockout"
+    type: Boolean
+    scope: Public
+    access: ReadWrite
+    api_name: "lockout"
+}
+
+# force all authenticate operations to fail
+prop {
+    prop_name: "vendor.face.virtual.operation_authenticate_fails"
+    type: Boolean
+    scope: Public
+    access: ReadWrite
+    api_name: "operation_authenticate_fails"
+}
+
+# force all detectInteraction operations to fail
+prop {
+    prop_name: "vendor.face.virtual.operation_detect_interaction_fails"
+    type: Boolean
+    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: Public
+    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: Integer
+    scope: Public
+    access: ReadWrite
+    api_name: "operation_authenticate_latency"
+}
+
+# add a latency to detectInteraction operations
+prop {
+    prop_name: "vendor.face.virtual.operation_detect_interaction_latency"
+    type: Integer
+    scope: Public
+    access: ReadWrite
+    api_name: "operation_detect_interaction_latency"
+}
+
+# millisecond duration for authenticate operations
+# (waits for changes to enrollment_hit)
+prop {
+    prop_name: "vendor.face.virtual.operation_authenticate_duration"
+    type: Integer
+    scope: Public
+    access: ReadWrite
+    api_name: "operation_authenticate_duration"
+}
diff --git a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
new file mode 100644
index 0000000..c8ad6b7
--- /dev/null
+++ b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/binder_process.h>
+#include <face.sysprop.h>
+#include <gtest/gtest.h>
+
+#include <aidl/android/hardware/biometrics/face/BnSessionCallback.h>
+#include <android-base/logging.h>
+
+#include "FakeFaceEngine.h"
+
+using namespace ::android::face::virt;
+using namespace ::aidl::android::hardware::biometrics::face;
+using namespace ::aidl::android::hardware::keymaster;
+
+namespace aidl::android::hardware::biometrics::face {
+
+class TestSessionCallback : public BnSessionCallback {
+  public:
+    ndk::ScopedAStatus onChallengeGenerated(int64_t challenge) override {
+        mLastChallenge = challenge;
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onChallengeRevoked(int64_t challenge) override {
+        mLastChallengeRevoked = challenge;
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onError(Error error, int32_t) override {
+        mError = error;
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onEnrollmentProgress(int32_t enrollmentId, int32_t remaining) override {
+        if (remaining == 0) mLastEnrolled = enrollmentId;
+        return ndk::ScopedAStatus::ok();
+    };
+
+    ::ndk::ScopedAStatus onAuthenticationSucceeded(int32_t enrollmentId,
+                                                   const HardwareAuthToken&) override {
+        mLastAuthenticated = enrollmentId;
+        mAuthenticateFailed = false;
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onAuthenticationFailed() override {
+        mLastAuthenticated = 0;
+        mAuthenticateFailed = true;
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onInteractionDetected() override {
+        mInteractionDetectedCount++;
+        return ndk::ScopedAStatus::ok();
+    };
+
+    ::ndk::ScopedAStatus onEnrollmentFrame(const EnrollmentFrame& frame) override {
+        mEnrollmentFrames.push_back(frame.data.vendorCode);
+        return ndk::ScopedAStatus::ok();
+    }
+
+    ::ndk::ScopedAStatus onEnrollmentsEnumerated(
+            const std::vector<int32_t>& enrollmentIds) override {
+        mLastEnrollmentsEnumerated = enrollmentIds;
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onEnrollmentsRemoved(const std::vector<int32_t>& enrollmentIds) override {
+        mLastEnrollmentRemoved = enrollmentIds;
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t authenticatorId) override {
+        mLastAuthenticatorId = authenticatorId;
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onAuthenticatorIdInvalidated(int64_t authenticatorId) override {
+        mLastAuthenticatorId = authenticatorId;
+        mAuthenticatorIdInvalidated = true;
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onAuthenticationFrame(const AuthenticationFrame& /*authFrame*/) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onLockoutPermanent() override {
+        mLockoutPermanent = true;
+        return ndk::ScopedAStatus::ok();
+    };
+    ::ndk::ScopedAStatus onLockoutTimed(int64_t /* timeout */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onLockoutCleared() override {
+        mLockoutPermanent = false;
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onSessionClosed() override { return ndk::ScopedAStatus::ok(); }
+
+    ::ndk::ScopedAStatus onFeaturesRetrieved(const std::vector<Feature>& features) override {
+        mFeatures = features;
+        return ndk::ScopedAStatus::ok();
+    }
+
+    ::ndk::ScopedAStatus onFeatureSet(Feature feature) override {
+        mLastFeatureSet = feature;
+        return ndk::ScopedAStatus::ok();
+    }
+
+    Error mError = Error::UNKNOWN;
+    int64_t mLastChallenge = -1;
+    int64_t mLastChallengeRevoked = -1;
+    int32_t mLastEnrolled = -1;
+    int32_t mLastAuthenticated = -1;
+    int64_t mLastAuthenticatorId = -1;
+    std::vector<int32_t> mLastEnrollmentsEnumerated;
+    std::vector<int32_t> mLastEnrollmentRemoved;
+    std::vector<Feature> mFeatures;
+    Feature mLastFeatureSet;
+    std::vector<int32_t> mEnrollmentFrames;
+    bool mAuthenticateFailed = false;
+    bool mAuthenticatorIdInvalidated = false;
+    bool mLockoutPermanent = false;
+    int mInteractionDetectedCount = 0;
+};
+
+class FakeFaceEngineTest : public ::testing::Test {
+  protected:
+    void SetUp() override {
+        LOG(ERROR) << "JRM SETUP";
+        mCallback = ndk::SharedRefBase::make<TestSessionCallback>();
+        FaceHalProperties::enrollments({});
+        FaceHalProperties::challenge({});
+        FaceHalProperties::features({});
+        FaceHalProperties::authenticator_id({});
+        FaceHalProperties::strength("");
+    }
+
+    FakeFaceEngine mEngine;
+    std::shared_ptr<TestSessionCallback> mCallback;
+    std::promise<void> mCancel;
+};
+
+TEST_F(FakeFaceEngineTest, one_eq_one) {
+    ASSERT_EQ(1, 1);
+}
+
+TEST_F(FakeFaceEngineTest, GenerateChallenge) {
+    mEngine.generateChallengeImpl(mCallback.get());
+    ASSERT_EQ(FaceHalProperties::challenge().value(), mCallback->mLastChallenge);
+}
+
+TEST_F(FakeFaceEngineTest, RevokeChallenge) {
+    auto challenge = FaceHalProperties::challenge().value_or(10);
+    mEngine.revokeChallengeImpl(mCallback.get(), challenge);
+    ASSERT_FALSE(FaceHalProperties::challenge().has_value());
+    ASSERT_EQ(challenge, mCallback->mLastChallengeRevoked);
+}
+
+TEST_F(FakeFaceEngineTest, ResetLockout) {
+    FaceHalProperties::lockout(true);
+    mEngine.resetLockoutImpl(mCallback.get(), {});
+    ASSERT_FALSE(mCallback->mLockoutPermanent);
+    ASSERT_FALSE(FaceHalProperties::lockout().value_or(true));
+}
+
+TEST_F(FakeFaceEngineTest, AuthenticatorId) {
+    FaceHalProperties::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);
+    mEngine.getAuthenticatorIdImpl(mCallback.get());
+    ASSERT_EQ(0, mCallback->mLastAuthenticatorId);
+    ASSERT_FALSE(mCallback->mAuthenticatorIdInvalidated);
+}
+
+TEST_F(FakeFaceEngineTest, AuthenticatorIdInvalidate) {
+    FaceHalProperties::authenticator_id(500);
+    mEngine.invalidateAuthenticatorIdImpl(mCallback.get());
+    ASSERT_NE(500, FaceHalProperties::authenticator_id().value());
+    ASSERT_TRUE(mCallback->mAuthenticatorIdInvalidated);
+}
+
+TEST_F(FakeFaceEngineTest, Enroll) {
+    FaceHalProperties::next_enrollment("1,0:30:true,1:0:true,2:0:true,3:0:true,4:0: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_EQ(1, mCallback->mLastEnrolled);
+}
+
+TEST_F(FakeFaceEngineTest, EnrollFails) {
+    FaceHalProperties::next_enrollment("1,0:30:true,1:0:true,2:0:true,3:0:true,4:0: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());
+}
+
+TEST_F(FakeFaceEngineTest, EnrollCancel) {
+    FaceHalProperties::next_enrollment("1,0:30:true,1:0:true,2:0:true,3:0:true,4:0: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_FALSE(FaceHalProperties::next_enrollment().has_value());
+}
+
+TEST_F(FakeFaceEngineTest, Authenticate) {
+    FaceHalProperties::enrollments({100});
+    FaceHalProperties::enrollment_hit(100);
+    mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
+
+    ASSERT_EQ(100, mCallback->mLastAuthenticated);
+    ASSERT_FALSE(mCallback->mAuthenticateFailed);
+}
+
+TEST_F(FakeFaceEngineTest, AuthenticateCancel) {
+    FaceHalProperties::enrollments({100});
+    FaceHalProperties::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);
+    mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
+    ASSERT_EQ(Error::UNABLE_TO_PROCESS, mCallback->mError);
+    ASSERT_TRUE(mCallback->mAuthenticateFailed);
+}
+
+TEST_F(FakeFaceEngineTest, DetectInteraction) {
+    FaceHalProperties::enrollments({100});
+    FaceHalProperties::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);
+    mCancel.set_value();
+    mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
+    ASSERT_EQ(Error::CANCELED, mCallback->mError);
+}
+
+TEST_F(FakeFaceEngineTest, GetFeatureEmpty) {
+    mEngine.getFeaturesImpl(mCallback.get());
+    ASSERT_TRUE(mCallback->mFeatures.empty());
+}
+
+TEST_F(FakeFaceEngineTest, SetFeature) {
+    FaceHalProperties::enrollments({1});
+    keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+    mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
+    auto features = mCallback->mFeatures;
+    ASSERT_TRUE(features.empty());
+    ASSERT_EQ(Feature::REQUIRE_ATTENTION, mCallback->mLastFeatureSet);
+
+    mEngine.getFeaturesImpl(mCallback.get());
+    features = mCallback->mFeatures;
+    ASSERT_FALSE(features.empty());
+    ASSERT_NE(features.end(),
+              std::find(features.begin(), features.end(), Feature::REQUIRE_ATTENTION));
+}
+
+TEST_F(FakeFaceEngineTest, ToggleFeature) {
+    FaceHalProperties::enrollments({1});
+    keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+    mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
+    mEngine.getFeaturesImpl(mCallback.get());
+    auto features = mCallback->mFeatures;
+    ASSERT_FALSE(features.empty());
+    ASSERT_NE(features.end(),
+              std::find(features.begin(), features.end(), Feature::REQUIRE_ATTENTION));
+
+    mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, false);
+    mEngine.getFeaturesImpl(mCallback.get());
+    features = mCallback->mFeatures;
+    ASSERT_TRUE(features.empty());
+}
+
+TEST_F(FakeFaceEngineTest, TurningOffNonExistentFeatureDoesNothing) {
+    FaceHalProperties::enrollments({1});
+    keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+    mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, false);
+    mEngine.getFeaturesImpl(mCallback.get());
+    auto features = mCallback->mFeatures;
+    ASSERT_TRUE(features.empty());
+}
+
+TEST_F(FakeFaceEngineTest, SetMultipleFeatures) {
+    FaceHalProperties::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);
+    mEngine.setFeatureImpl(mCallback.get(), hat, Feature::DEBUG, true);
+    mEngine.getFeaturesImpl(mCallback.get());
+    auto features = mCallback->mFeatures;
+    ASSERT_EQ(3, features.size());
+    ASSERT_NE(features.end(),
+              std::find(features.begin(), features.end(), Feature::REQUIRE_ATTENTION));
+    ASSERT_NE(features.end(),
+              std::find(features.begin(), features.end(), Feature::REQUIRE_DIVERSE_POSES));
+    ASSERT_NE(features.end(), std::find(features.begin(), features.end(), Feature::DEBUG));
+}
+
+TEST_F(FakeFaceEngineTest, SetMultipleFeaturesAndTurnOffSome) {
+    FaceHalProperties::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);
+    mEngine.setFeatureImpl(mCallback.get(), hat, Feature::DEBUG, true);
+    mEngine.setFeatureImpl(mCallback.get(), hat, Feature::DEBUG, false);
+    mEngine.getFeaturesImpl(mCallback.get());
+    auto features = mCallback->mFeatures;
+    ASSERT_EQ(2, features.size());
+    ASSERT_NE(features.end(),
+              std::find(features.begin(), features.end(), Feature::REQUIRE_ATTENTION));
+    ASSERT_NE(features.end(),
+              std::find(features.begin(), features.end(), Feature::REQUIRE_DIVERSE_POSES));
+    ASSERT_EQ(features.end(), std::find(features.begin(), features.end(), Feature::DEBUG));
+}
+
+TEST_F(FakeFaceEngineTest, Enumerate) {
+    FaceHalProperties::enrollments({120, 3});
+    mEngine.enumerateEnrollmentsImpl(mCallback.get());
+    auto enrolls = mCallback->mLastEnrollmentsEnumerated;
+    ASSERT_FALSE(enrolls.empty());
+    ASSERT_NE(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 120));
+    ASSERT_NE(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 3));
+}
+
+TEST_F(FakeFaceEngineTest, RemoveEnrollments) {
+    FaceHalProperties::enrollments({120, 3, 100});
+    mEngine.removeEnrollmentsImpl(mCallback.get(), {120, 100});
+    mEngine.enumerateEnrollmentsImpl(mCallback.get());
+    auto enrolls = mCallback->mLastEnrollmentsEnumerated;
+    ASSERT_FALSE(enrolls.empty());
+    ASSERT_EQ(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 120));
+    ASSERT_NE(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 3));
+    ASSERT_EQ(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 100));
+}
+
+TEST_F(FakeFaceEngineTest, ResetLockoutWithAuth) {
+    FaceHalProperties::lockout(true);
+    FaceHalProperties::enrollments({33});
+    FaceHalProperties::enrollment_hit(33);
+    auto cancelFuture = mCancel.get_future();
+    mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, cancelFuture);
+
+    ASSERT_TRUE(mCallback->mLockoutPermanent);
+
+    mEngine.resetLockoutImpl(mCallback.get(), {} /* hat */);
+    ASSERT_FALSE(mCallback->mLockoutPermanent);
+    FaceHalProperties::enrollment_hit(33);
+    mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, cancelFuture);
+    ASSERT_EQ(33, mCallback->mLastAuthenticated);
+    ASSERT_FALSE(mCallback->mAuthenticateFailed);
+}
+
+}  // namespace aidl::android::hardware::biometrics::face
\ No newline at end of file
diff --git a/biometrics/fingerprint/aidl/OWNERS b/biometrics/fingerprint/aidl/OWNERS
index 36d7261..e162d2d 100644
--- a/biometrics/fingerprint/aidl/OWNERS
+++ b/biometrics/fingerprint/aidl/OWNERS
@@ -1,2 +1,4 @@
 ilyamaty@google.com
-kchyn@google.com
+jeffpu@google.com
+jbolinger@google.com
+joshmccloskey@google.com
diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp
index 70fadfe..2aa7bbd 100644
--- a/biometrics/fingerprint/aidl/default/Android.bp
+++ b/biometrics/fingerprint/aidl/default/Android.bp
@@ -15,11 +15,9 @@
     vintf_fragments: ["fingerprint-example.xml"],
     local_include_dirs: ["include"],
     srcs: [
-        "CancellationSignal.cpp",
         "FakeFingerprintEngine.cpp",
         "Fingerprint.cpp",
         "Session.cpp",
-        "WorkerThread.cpp",
         "main.cpp",
     ],
     shared_libs: [
@@ -27,28 +25,16 @@
         "libbinder_ndk",
         "android.hardware.biometrics.fingerprint-V2-ndk",
         "android.hardware.biometrics.common-V2-ndk",
+        "android.hardware.biometrics.common.thread",
+        "android.hardware.biometrics.common.util",
     ],
-    static_libs: ["android.hardware.biometrics.fingerprint.VirtualProps"],
-}
-
-cc_test_host {
-    name: "android.hardware.biometrics.fingerprint.WorkerThreadTest",
-    local_include_dirs: ["include"],
-    srcs: [
-        "tests/WorkerThreadTest.cpp",
-        "WorkerThread.cpp",
-    ],
-    shared_libs: [
-        "libcutils",
-    ],
-    test_suites: ["general-tests"],
+    static_libs: ["libandroid.hardware.biometrics.fingerprint.VirtualProps"],
 }
 
 cc_test {
     name: "android.hardware.biometrics.fingerprint.FakeFingerprintEngineTest",
     local_include_dirs: ["include"],
     srcs: [
-        "CancellationSignal.cpp",
         "tests/FakeFingerprintEngineTest.cpp",
         "FakeFingerprintEngine.cpp",
     ],
@@ -57,10 +43,11 @@
         "libbinder_ndk",
     ],
     static_libs: [
-        "android.hardware.biometrics.fingerprint.VirtualProps",
+        "libandroid.hardware.biometrics.fingerprint.VirtualProps",
         "android.hardware.biometrics.fingerprint-V2-ndk",
         "android.hardware.biometrics.common-V2-ndk",
         "android.hardware.keymaster-V3-ndk",
+        "android.hardware.biometrics.common.util",
     ],
     vendor: true,
     test_suites: ["general-tests"],
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
index d1fe183..138caa0 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
@@ -16,53 +16,14 @@
 
 #include "FakeFingerprintEngine.h"
 
-#include <fingerprint.sysprop.h>
-#include "CancellationSignal.h"
-
 #include <android-base/logging.h>
-#include <chrono>
-#include <regex>
-#include <thread>
 
-#define SLEEP_MS(x) \
-    if (x > 0) std::this_thread::sleep_for(std::chrono::milliseconds(x))
-#define BEGIN_OP(x)            \
-    do {                       \
-        LOG(INFO) << __func__; \
-        SLEEP_MS(x);           \
-    } while (0)
-#define IS_TRUE(x) ((x == "1") || (x == "true"))
+#include <fingerprint.sysprop.h>
 
-// This is for non-test situations, such as casual cuttlefish users, that don't
-// set an explicit value.
-// Some operations (i.e. enroll, authenticate) will be executed in tight loops
-// by parts of the UI or fail if there is no latency. For example, the
-// fingerprint settings page constantly runs auth and the enrollment UI uses a
-// cancel/restart cycle that requires some latency while the activities change.
-#define DEFAULT_LATENCY 2000
+#include "util/CancellationSignal.h"
+#include "util/Util.h"
 
 using namespace ::android::fingerprint::virt;
-using namespace ::aidl::android::hardware::biometrics::fingerprint;
-
-int64_t getSystemNanoTime() {
-    timespec now;
-    clock_gettime(CLOCK_MONOTONIC, &now);
-    return now.tv_sec * 1000000000LL + now.tv_nsec;
-}
-
-bool hasElapsed(int64_t start, int64_t durationMillis) {
-    auto now = getSystemNanoTime();
-    if (now < start) return true;
-    if (durationMillis <= 0) return true;
-    return ((now - start) / 1000000LL) > durationMillis;
-}
-
-std::vector<std::string> split(const std::string& str, const std::string& sep) {
-    std::regex regex(sep);
-    std::vector<std::string> parts(std::sregex_token_iterator(str.begin(), str.end(), regex, -1),
-                                   std::sregex_token_iterator());
-    return parts;
-}
 
 namespace aidl::android::hardware::biometrics::fingerprint {
 
@@ -100,14 +61,14 @@
 
     // format is "<id>:<progress_ms>,<progress_ms>,...:<result>
     auto nextEnroll = FingerprintHalProperties::next_enrollment().value_or("");
-    auto parts = split(nextEnroll, ":");
+    auto parts = Util::split(nextEnroll, ":");
     if (parts.size() != 3) {
         LOG(ERROR) << "Fail: invalid next_enrollment";
         cb->onError(Error::VENDOR, 0 /* vendorError */);
         return;
     }
     auto enrollmentId = std::stoi(parts[0]);
-    auto progress = split(parts[1], ",");
+    auto progress = Util::split(parts[1], ",");
     for (size_t i = 0; i < progress.size(); i++) {
         auto left = progress.size() - i - 1;
         SLEEP_MS(std::stoi(progress[i]));
@@ -140,7 +101,7 @@
                                              const std::future<void>& cancel) {
     BEGIN_OP(FingerprintHalProperties::operation_authenticate_latency().value_or(DEFAULT_LATENCY));
 
-    auto now = getSystemNanoTime();
+    auto now = Util::getSystemNanoTime();
     int64_t duration = FingerprintHalProperties::operation_authenticate_duration().value_or(0);
     do {
         if (FingerprintHalProperties::operation_authenticate_fails().value_or(false)) {
@@ -171,7 +132,7 @@
         }
 
         SLEEP_MS(100);
-    } while (!hasElapsed(now, duration));
+    } while (!Util::hasElapsed(now, duration));
 
     LOG(ERROR) << "Fail: not enrolled";
     cb->onAuthenticationFailed();
diff --git a/biometrics/fingerprint/aidl/default/Session.cpp b/biometrics/fingerprint/aidl/default/Session.cpp
index 078d3d9..ab91e98 100644
--- a/biometrics/fingerprint/aidl/default/Session.cpp
+++ b/biometrics/fingerprint/aidl/default/Session.cpp
@@ -18,7 +18,7 @@
 
 #include <android-base/logging.h>
 
-#include "CancellationSignal.h"
+#include "util/CancellationSignal.h"
 
 namespace aidl::android::hardware::biometrics::fingerprint {
 
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
index 8659b79..eb810da 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
@@ -15,12 +15,13 @@
  */
 
 #pragma once
-
+#include <aidl/android/hardware/biometrics/common/SensorStrength.h>
 #include <aidl/android/hardware/biometrics/fingerprint/ISessionCallback.h>
 
 #include <random>
 
-#include "CancellationSignal.h"
+#include <future>
+#include <vector>
 
 using namespace ::aidl::android::hardware::biometrics::common;
 
diff --git a/biometrics/fingerprint/aidl/default/include/Fingerprint.h b/biometrics/fingerprint/aidl/default/include/Fingerprint.h
index 7bd3d6d..20def0c 100644
--- a/biometrics/fingerprint/aidl/default/include/Fingerprint.h
+++ b/biometrics/fingerprint/aidl/default/include/Fingerprint.h
@@ -20,7 +20,7 @@
 
 #include "FakeFingerprintEngine.h"
 #include "Session.h"
-#include "WorkerThread.h"
+#include "thread/WorkerThread.h"
 
 namespace aidl::android::hardware::biometrics::fingerprint {
 
diff --git a/biometrics/fingerprint/aidl/default/include/Session.h b/biometrics/fingerprint/aidl/default/include/Session.h
index acd5def..104d819 100644
--- a/biometrics/fingerprint/aidl/default/include/Session.h
+++ b/biometrics/fingerprint/aidl/default/include/Session.h
@@ -20,7 +20,7 @@
 #include <aidl/android/hardware/biometrics/fingerprint/ISessionCallback.h>
 
 #include "FakeFingerprintEngine.h"
-#include "WorkerThread.h"
+#include "thread/WorkerThread.h"
 
 namespace aidl::android::hardware::biometrics::fingerprint {
 
diff --git a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
index d64751a..98b62ef 100644
--- a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
+++ b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
@@ -20,8 +20,11 @@
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
     </target_preparer>
 
-    <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
-        <option name="bluetooth" value="off" />
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="settings put global ble_scan_always_enabled 0" />
+        <option name="run-command" value="su u$(am get-current-user)_system svc bluetooth disable" />
+        <option name="teardown-command" value="su u$(am get-current-user)_system svc bluetooth enable" />
+        <option name="teardown-command" value="settings put global ble_scan_always_enabled 1" />
     </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index cd6617b..a687162 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -40,9 +40,6 @@
             enabled: false,
         },
         ndk: {
-            vndk: {
-                enabled: true,
-            },
             apex_available: [
                 "//apex_available:platform",
                 "com.android.bluetooth",
@@ -59,6 +56,15 @@
                 "android.hardware.audio.common-V1",
             ],
         },
+        {
+            version: "2",
+            imports: [
+                "android.hardware.common-V2",
+                "android.hardware.common.fmq-V1",
+                "android.hardware.audio.common-V1",
+            ],
+        },
+
     ],
 
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/.hash b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/.hash
new file mode 100644
index 0000000..52e6933
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/.hash
@@ -0,0 +1 @@
+b82d5b9f717bbf63bef774ee8f72572065ca61ce
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AacCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AacCapabilities.aidl
new file mode 100644
index 0000000..899b8ca
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AacCapabilities.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable AacCapabilities {
+  android.hardware.bluetooth.audio.AacObjectType[] objectType;
+  int[] sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+  boolean variableBitRateSupported;
+  byte[] bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AacConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AacConfiguration.aidl
new file mode 100644
index 0000000..6adef6d
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AacConfiguration.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable AacConfiguration {
+  android.hardware.bluetooth.audio.AacObjectType objectType;
+  int sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode channelMode;
+  boolean variableBitRateEnabled;
+  byte bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AacObjectType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AacObjectType.aidl
new file mode 100644
index 0000000..2148244
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AacObjectType.aidl
@@ -0,0 +1,41 @@
+/*
+ * 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.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum AacObjectType {
+  MPEG2_LC = 0,
+  MPEG4_LC = 1,
+  MPEG4_LTP = 2,
+  MPEG4_SCALABLE = 3,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxAdaptiveCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxAdaptiveCapabilities.aidl
new file mode 100644
index 0000000..4e5dfe6
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxAdaptiveCapabilities.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable AptxAdaptiveCapabilities {
+  int[] sampleRateHz;
+  android.hardware.bluetooth.audio.AptxAdaptiveChannelMode[] channelMode;
+  byte[] bitsPerSample;
+  android.hardware.bluetooth.audio.AptxMode[] aptxMode;
+  android.hardware.bluetooth.audio.AptxSinkBuffering sinkBufferingMs;
+  android.hardware.bluetooth.audio.AptxAdaptiveTimeToPlay ttp;
+  android.hardware.bluetooth.audio.AptxAdaptiveInputMode inputMode;
+  int inputFadeDurationMs;
+  byte[] aptxAdaptiveConfigStream;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl
new file mode 100644
index 0000000..0499b70
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxAdaptiveChannelMode.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="int") @VintfStability
+enum AptxAdaptiveChannelMode {
+  JOINT_STEREO = 0,
+  MONO = 1,
+  DUAL_MONO = 2,
+  TWS_STEREO = 4,
+  UNKNOWN = 255,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxAdaptiveConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxAdaptiveConfiguration.aidl
new file mode 100644
index 0000000..aab0521
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxAdaptiveConfiguration.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable AptxAdaptiveConfiguration {
+  int sampleRateHz;
+  android.hardware.bluetooth.audio.AptxAdaptiveChannelMode channelMode;
+  byte bitsPerSample;
+  android.hardware.bluetooth.audio.AptxMode aptxMode;
+  android.hardware.bluetooth.audio.AptxSinkBuffering sinkBufferingMs;
+  android.hardware.bluetooth.audio.AptxAdaptiveTimeToPlay ttp;
+  android.hardware.bluetooth.audio.AptxAdaptiveInputMode inputMode;
+  int inputFadeDurationMs;
+  byte[] aptxAdaptiveConfigStream;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl
new file mode 100644
index 0000000..f702939
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxAdaptiveInputMode.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="int") @VintfStability
+enum AptxAdaptiveInputMode {
+  STEREO = 0,
+  DUAL_MONO = 1,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxAdaptiveTimeToPlay.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxAdaptiveTimeToPlay.aidl
new file mode 100644
index 0000000..3560666
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxAdaptiveTimeToPlay.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable AptxAdaptiveTimeToPlay {
+  byte lowLowLatency;
+  byte highLowLatency;
+  byte lowHighQuality;
+  byte highHighQuality;
+  byte lowTws;
+  byte highTws;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxCapabilities.aidl
new file mode 100644
index 0000000..08a38e2
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxCapabilities.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable AptxCapabilities {
+  int[] sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+  byte[] bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxConfiguration.aidl
new file mode 100644
index 0000000..91e88b3
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxConfiguration.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable AptxConfiguration {
+  int sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode channelMode;
+  byte bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxMode.aidl
new file mode 100644
index 0000000..d5dd9d9
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxMode.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="int") @VintfStability
+enum AptxMode {
+  UNKNOWN = 0,
+  HIGH_QUALITY = 4096,
+  LOW_LATENCY = 8192,
+  ULTRA_LOW_LATENCY = 16384,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxSinkBuffering.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxSinkBuffering.aidl
new file mode 100644
index 0000000..527418e
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AptxSinkBuffering.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable AptxSinkBuffering {
+  byte minLowLatency;
+  byte maxLowLatency;
+  byte minHighQuality;
+  byte maxHighQuality;
+  byte minTws;
+  byte maxTws;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AudioCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AudioCapabilities.aidl
new file mode 100644
index 0000000..8ae716f
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AudioCapabilities.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+union AudioCapabilities {
+  android.hardware.bluetooth.audio.PcmCapabilities pcmCapabilities;
+  android.hardware.bluetooth.audio.CodecCapabilities a2dpCapabilities;
+  android.hardware.bluetooth.audio.LeAudioCodecCapabilitiesSetting leAudioCapabilities;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AudioConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AudioConfiguration.aidl
new file mode 100644
index 0000000..3abfb31
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AudioConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+union AudioConfiguration {
+  android.hardware.bluetooth.audio.PcmConfiguration pcmConfig;
+  android.hardware.bluetooth.audio.CodecConfiguration a2dpConfig;
+  android.hardware.bluetooth.audio.LeAudioConfiguration leAudioConfig;
+  android.hardware.bluetooth.audio.LeAudioBroadcastConfiguration leAudioBroadcastConfig;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AudioLocation.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AudioLocation.aidl
new file mode 100644
index 0000000..319a5e2
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/AudioLocation.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="int") @VintfStability
+enum AudioLocation {
+  UNKNOWN = 1,
+  FRONT_LEFT = 2,
+  FRONT_RIGHT = 4,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/BluetoothAudioStatus.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/BluetoothAudioStatus.aidl
new file mode 100644
index 0000000..c20c057
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/BluetoothAudioStatus.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="int") @VintfStability
+enum BluetoothAudioStatus {
+  UNKNOWN = 0,
+  SUCCESS = 1,
+  UNSUPPORTED_CODEC_CONFIGURATION = 2,
+  FAILURE = 3,
+  RECONFIGURATION = 4,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/BroadcastCapability.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/BroadcastCapability.aidl
new file mode 100644
index 0000000..58710ef
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/BroadcastCapability.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable BroadcastCapability {
+  android.hardware.bluetooth.audio.CodecType codecType;
+  android.hardware.bluetooth.audio.AudioLocation supportedChannel;
+  int channelCountPerStream;
+  android.hardware.bluetooth.audio.BroadcastCapability.LeAudioCodecCapabilities leAudioCodecCapabilities;
+  @VintfStability
+  parcelable VendorCapabilities {
+    ParcelableHolder extension;
+  }
+  @VintfStability
+  union LeAudioCodecCapabilities {
+    @nullable android.hardware.bluetooth.audio.Lc3Capabilities[] lc3Capabilities;
+    @nullable android.hardware.bluetooth.audio.BroadcastCapability.VendorCapabilities[] vendorCapabillities;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/ChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/ChannelMode.aidl
new file mode 100644
index 0000000..feacb80
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/ChannelMode.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum ChannelMode {
+  UNKNOWN = 0,
+  MONO = 1,
+  STEREO = 2,
+  DUALMONO = 3,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/CodecCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/CodecCapabilities.aidl
new file mode 100644
index 0000000..b00649a
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/CodecCapabilities.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable CodecCapabilities {
+  android.hardware.bluetooth.audio.CodecType codecType;
+  android.hardware.bluetooth.audio.CodecCapabilities.Capabilities capabilities;
+  @VintfStability
+  parcelable VendorCapabilities {
+    ParcelableHolder extension;
+  }
+  @VintfStability
+  union Capabilities {
+    android.hardware.bluetooth.audio.SbcCapabilities sbcCapabilities;
+    android.hardware.bluetooth.audio.AacCapabilities aacCapabilities;
+    android.hardware.bluetooth.audio.LdacCapabilities ldacCapabilities;
+    android.hardware.bluetooth.audio.AptxCapabilities aptxCapabilities;
+    android.hardware.bluetooth.audio.AptxAdaptiveCapabilities aptxAdaptiveCapabilities;
+    android.hardware.bluetooth.audio.Lc3Capabilities lc3Capabilities;
+    android.hardware.bluetooth.audio.CodecCapabilities.VendorCapabilities vendorCapabilities;
+    @nullable android.hardware.bluetooth.audio.OpusCapabilities opusCapabilities;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/CodecConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/CodecConfiguration.aidl
new file mode 100644
index 0000000..7f5ea48
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/CodecConfiguration.aidl
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable CodecConfiguration {
+  android.hardware.bluetooth.audio.CodecType codecType;
+  int encodedAudioBitrate;
+  int peerMtu;
+  boolean isScmstEnabled;
+  android.hardware.bluetooth.audio.CodecConfiguration.CodecSpecific config;
+  @VintfStability
+  parcelable VendorConfiguration {
+    int vendorId;
+    char codecId;
+    ParcelableHolder codecConfig;
+  }
+  @VintfStability
+  union CodecSpecific {
+    android.hardware.bluetooth.audio.SbcConfiguration sbcConfig;
+    android.hardware.bluetooth.audio.AacConfiguration aacConfig;
+    android.hardware.bluetooth.audio.LdacConfiguration ldacConfig;
+    android.hardware.bluetooth.audio.AptxConfiguration aptxConfig;
+    android.hardware.bluetooth.audio.AptxAdaptiveConfiguration aptxAdaptiveConfig;
+    android.hardware.bluetooth.audio.Lc3Configuration lc3Config;
+    android.hardware.bluetooth.audio.CodecConfiguration.VendorConfiguration vendorConfig;
+    @nullable android.hardware.bluetooth.audio.OpusConfiguration opusConfig;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/CodecType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/CodecType.aidl
new file mode 100644
index 0000000..d1723e6
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/CodecType.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="int") @VintfStability
+enum CodecType {
+  UNKNOWN = 0,
+  SBC = 1,
+  AAC = 2,
+  APTX = 3,
+  APTX_HD = 4,
+  LDAC = 5,
+  LC3 = 6,
+  VENDOR = 7,
+  APTX_ADAPTIVE = 8,
+  OPUS = 9,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl
new file mode 100644
index 0000000..d364371
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+interface IBluetoothAudioPort {
+  android.hardware.bluetooth.audio.PresentationPosition getPresentationPosition();
+  void startStream(boolean isLowLatency);
+  void stopStream();
+  void suspendStream();
+  void updateSourceMetadata(in android.hardware.audio.common.SourceMetadata sourceMetadata);
+  void updateSinkMetadata(in android.hardware.audio.common.SinkMetadata sinkMetadata);
+  void setLatencyMode(in android.hardware.bluetooth.audio.LatencyMode latencyMode);
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
new file mode 100644
index 0000000..267af0f
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+interface IBluetoothAudioProvider {
+  void endSession();
+  android.hardware.common.fmq.MQDescriptor<byte,android.hardware.common.fmq.SynchronizedReadWrite> startSession(in android.hardware.bluetooth.audio.IBluetoothAudioPort hostIf, in android.hardware.bluetooth.audio.AudioConfiguration audioConfig, in android.hardware.bluetooth.audio.LatencyMode[] supportedLatencyModes);
+  void streamStarted(in android.hardware.bluetooth.audio.BluetoothAudioStatus status);
+  void streamSuspended(in android.hardware.bluetooth.audio.BluetoothAudioStatus status);
+  void updateAudioConfiguration(in android.hardware.bluetooth.audio.AudioConfiguration audioConfig);
+  void setLowLatencyModeAllowed(in boolean allowed);
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
new file mode 100644
index 0000000..5e33deb
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+interface IBluetoothAudioProviderFactory {
+  android.hardware.bluetooth.audio.AudioCapabilities[] getProviderCapabilities(in android.hardware.bluetooth.audio.SessionType sessionType);
+  android.hardware.bluetooth.audio.IBluetoothAudioProvider openProvider(in android.hardware.bluetooth.audio.SessionType sessionType);
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LatencyMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LatencyMode.aidl
new file mode 100644
index 0000000..5583679
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LatencyMode.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@Backing(type="int") @VintfStability
+enum LatencyMode {
+  UNKNOWN = 0,
+  LOW_LATENCY = 1,
+  FREE = 2,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/Lc3Capabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/Lc3Capabilities.aidl
new file mode 100644
index 0000000..cc4449a
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/Lc3Capabilities.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable Lc3Capabilities {
+  byte[] pcmBitDepth;
+  int[] samplingFrequencyHz;
+  int[] frameDurationUs;
+  int[] octetsPerFrame;
+  byte[] blocksPerSdu;
+  android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/Lc3Configuration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/Lc3Configuration.aidl
new file mode 100644
index 0000000..7e8dccf
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/Lc3Configuration.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable Lc3Configuration {
+  byte pcmBitDepth;
+  int samplingFrequencyHz;
+  int frameDurationUs;
+  int octetsPerFrame;
+  byte blocksPerSdu;
+  android.hardware.bluetooth.audio.ChannelMode channelMode;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LdacCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LdacCapabilities.aidl
new file mode 100644
index 0000000..aa4e4c8
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LdacCapabilities.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable LdacCapabilities {
+  int[] sampleRateHz;
+  android.hardware.bluetooth.audio.LdacChannelMode[] channelMode;
+  android.hardware.bluetooth.audio.LdacQualityIndex[] qualityIndex;
+  byte[] bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LdacChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LdacChannelMode.aidl
new file mode 100644
index 0000000..88d6faf
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LdacChannelMode.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum LdacChannelMode {
+  UNKNOWN = 0,
+  STEREO = 1,
+  DUAL = 2,
+  MONO = 3,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LdacConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LdacConfiguration.aidl
new file mode 100644
index 0000000..8a37638
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LdacConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable LdacConfiguration {
+  int sampleRateHz;
+  android.hardware.bluetooth.audio.LdacChannelMode channelMode;
+  android.hardware.bluetooth.audio.LdacQualityIndex qualityIndex;
+  byte bitsPerSample;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LdacQualityIndex.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
new file mode 100644
index 0000000..35e4358
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LdacQualityIndex.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum LdacQualityIndex {
+  HIGH = 0,
+  MID = 1,
+  LOW = 2,
+  ABR = 3,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl
new file mode 100644
index 0000000..7d53b0c
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LeAudioBroadcastConfiguration.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable LeAudioBroadcastConfiguration {
+  android.hardware.bluetooth.audio.CodecType codecType;
+  android.hardware.bluetooth.audio.LeAudioBroadcastConfiguration.BroadcastStreamMap[] streamMap;
+  @VintfStability
+  parcelable BroadcastStreamMap {
+    char streamHandle;
+    int audioChannelAllocation;
+    android.hardware.bluetooth.audio.LeAudioCodecConfiguration leAudioCodecConfig;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.aidl
new file mode 100644
index 0000000..9818d54
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.bluetooth.audio;
+@VintfStability
+parcelable LeAudioCodecCapabilitiesSetting {
+  android.hardware.bluetooth.audio.UnicastCapability unicastEncodeCapability;
+  android.hardware.bluetooth.audio.UnicastCapability unicastDecodeCapability;
+  android.hardware.bluetooth.audio.BroadcastCapability broadcastCapability;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl
new file mode 100644
index 0000000..bb3d7e4
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LeAudioCodecConfiguration.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+union LeAudioCodecConfiguration {
+  android.hardware.bluetooth.audio.Lc3Configuration lc3Config;
+  android.hardware.bluetooth.audio.LeAudioCodecConfiguration.VendorConfiguration vendorConfig;
+  @VintfStability
+  parcelable VendorConfiguration {
+    ParcelableHolder extension;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
new file mode 100644
index 0000000..edb6795
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/LeAudioConfiguration.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable LeAudioConfiguration {
+  android.hardware.bluetooth.audio.CodecType codecType;
+  android.hardware.bluetooth.audio.LeAudioConfiguration.StreamMap[] streamMap;
+  int peerDelayUs;
+  android.hardware.bluetooth.audio.LeAudioCodecConfiguration leAudioCodecConfig;
+  @VintfStability
+  parcelable StreamMap {
+    char streamHandle;
+    int audioChannelAllocation;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/OpusCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/OpusCapabilities.aidl
new file mode 100644
index 0000000..2781893
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/OpusCapabilities.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable OpusCapabilities {
+  byte[] pcmBitDepth;
+  int[] samplingFrequencyHz;
+  int[] frameDurationUs;
+  int[] octetsPerFrame;
+  byte[] blocksPerSdu;
+  android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/OpusConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/OpusConfiguration.aidl
new file mode 100644
index 0000000..067690e
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/OpusConfiguration.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable OpusConfiguration {
+  byte pcmBitDepth;
+  int samplingFrequencyHz;
+  int frameDurationUs;
+  int octetsPerFrame;
+  byte blocksPerSdu;
+  android.hardware.bluetooth.audio.ChannelMode channelMode;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/PcmCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/PcmCapabilities.aidl
new file mode 100644
index 0000000..0c2f87d
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/PcmCapabilities.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable PcmCapabilities {
+  int[] sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+  byte[] bitsPerSample;
+  int[] dataIntervalUs;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/PcmConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/PcmConfiguration.aidl
new file mode 100644
index 0000000..93d7805
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/PcmConfiguration.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable PcmConfiguration {
+  int sampleRateHz;
+  android.hardware.bluetooth.audio.ChannelMode channelMode;
+  byte bitsPerSample;
+  int dataIntervalUs;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/PresentationPosition.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/PresentationPosition.aidl
new file mode 100644
index 0000000..7e997e8
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/PresentationPosition.aidl
@@ -0,0 +1,45 @@
+/*
+ * 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.bluetooth.audio;
+@VintfStability
+parcelable PresentationPosition {
+  long remoteDeviceAudioDelayNanos;
+  long transmittedOctets;
+  android.hardware.bluetooth.audio.PresentationPosition.TimeSpec transmittedOctetsTimestamp;
+  @VintfStability
+  parcelable TimeSpec {
+    long tvSec;
+    long tvNSec;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/SbcAllocMethod.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
new file mode 100644
index 0000000..091f6d7
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/SbcAllocMethod.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum SbcAllocMethod {
+  ALLOC_MD_S = 0,
+  ALLOC_MD_L = 1,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/SbcCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/SbcCapabilities.aidl
new file mode 100644
index 0000000..c8d7e7e
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/SbcCapabilities.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable SbcCapabilities {
+  int[] sampleRateHz;
+  android.hardware.bluetooth.audio.SbcChannelMode[] channelMode;
+  byte[] blockLength;
+  byte[] numSubbands;
+  android.hardware.bluetooth.audio.SbcAllocMethod[] allocMethod;
+  byte[] bitsPerSample;
+  int minBitpool;
+  int maxBitpool;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/SbcChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/SbcChannelMode.aidl
new file mode 100644
index 0000000..6441a99
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/SbcChannelMode.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum SbcChannelMode {
+  UNKNOWN = 0,
+  JOINT_STEREO = 1,
+  STEREO = 2,
+  DUAL = 3,
+  MONO = 4,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/SbcConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/SbcConfiguration.aidl
new file mode 100644
index 0000000..8eab9c3
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/SbcConfiguration.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable SbcConfiguration {
+  int sampleRateHz;
+  android.hardware.bluetooth.audio.SbcChannelMode channelMode;
+  byte blockLength;
+  byte numSubbands;
+  android.hardware.bluetooth.audio.SbcAllocMethod allocMethod;
+  byte bitsPerSample;
+  int minBitpool;
+  int maxBitpool;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/SessionType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/SessionType.aidl
new file mode 100644
index 0000000..33a3187
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/SessionType.aidl
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@Backing(type="byte") @VintfStability
+enum SessionType {
+  UNKNOWN = 0,
+  A2DP_SOFTWARE_ENCODING_DATAPATH = 1,
+  A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH = 2,
+  HEARING_AID_SOFTWARE_ENCODING_DATAPATH = 3,
+  LE_AUDIO_SOFTWARE_ENCODING_DATAPATH = 4,
+  LE_AUDIO_SOFTWARE_DECODING_DATAPATH = 5,
+  LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH = 6,
+  LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH = 7,
+  LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH = 8,
+  LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH = 9,
+  A2DP_SOFTWARE_DECODING_DATAPATH = 10,
+  A2DP_HARDWARE_OFFLOAD_DECODING_DATAPATH = 11,
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/UnicastCapability.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/UnicastCapability.aidl
new file mode 100644
index 0000000..130fef9
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/2/android/hardware/bluetooth/audio/UnicastCapability.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable UnicastCapability {
+  android.hardware.bluetooth.audio.CodecType codecType;
+  android.hardware.bluetooth.audio.AudioLocation supportedChannel;
+  int deviceCount;
+  int channelCountPerDevice;
+  android.hardware.bluetooth.audio.UnicastCapability.LeAudioCodecCapabilities leAudioCodecCapabilities;
+  @VintfStability
+  parcelable VendorCapabilities {
+    ParcelableHolder extension;
+  }
+  @VintfStability
+  union LeAudioCodecCapabilities {
+    android.hardware.bluetooth.audio.Lc3Capabilities lc3Capabilities;
+    android.hardware.bluetooth.audio.UnicastCapability.VendorCapabilities vendorCapabillities;
+  }
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl
index c3bc741..feacb80 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/ChannelMode.aidl
@@ -37,4 +37,5 @@
   UNKNOWN = 0,
   MONO = 1,
   STEREO = 2,
+  DUALMONO = 3,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecCapabilities.aidl
index 6efdcb7..b00649a 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecCapabilities.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecCapabilities.aidl
@@ -49,5 +49,6 @@
     android.hardware.bluetooth.audio.AptxAdaptiveCapabilities aptxAdaptiveCapabilities;
     android.hardware.bluetooth.audio.Lc3Capabilities lc3Capabilities;
     android.hardware.bluetooth.audio.CodecCapabilities.VendorCapabilities vendorCapabilities;
+    @nullable android.hardware.bluetooth.audio.OpusCapabilities opusCapabilities;
   }
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecConfiguration.aidl
index 77a6b1b..7f5ea48 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecConfiguration.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecConfiguration.aidl
@@ -54,5 +54,6 @@
     android.hardware.bluetooth.audio.AptxAdaptiveConfiguration aptxAdaptiveConfig;
     android.hardware.bluetooth.audio.Lc3Configuration lc3Config;
     android.hardware.bluetooth.audio.CodecConfiguration.VendorConfiguration vendorConfig;
+    @nullable android.hardware.bluetooth.audio.OpusConfiguration opusConfig;
   }
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
index 1522cb4..d1723e6 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
@@ -43,4 +43,5 @@
   LC3 = 6,
   VENDOR = 7,
   APTX_ADAPTIVE = 8,
+  OPUS = 9,
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/OpusCapabilities.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/OpusCapabilities.aidl
new file mode 100644
index 0000000..2781893
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/OpusCapabilities.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable OpusCapabilities {
+  byte[] pcmBitDepth;
+  int[] samplingFrequencyHz;
+  int[] frameDurationUs;
+  int[] octetsPerFrame;
+  byte[] blocksPerSdu;
+  android.hardware.bluetooth.audio.ChannelMode[] channelMode;
+}
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/OpusConfiguration.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/OpusConfiguration.aidl
new file mode 100644
index 0000000..067690e
--- /dev/null
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/OpusConfiguration.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.bluetooth.audio;
+@VintfStability
+parcelable OpusConfiguration {
+  byte pcmBitDepth;
+  int samplingFrequencyHz;
+  int frameDurationUs;
+  int octetsPerFrame;
+  byte blocksPerSdu;
+  android.hardware.bluetooth.audio.ChannelMode channelMode;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/ChannelMode.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/ChannelMode.aidl
index 6613872..128089e 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/ChannelMode.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/ChannelMode.aidl
@@ -22,4 +22,5 @@
     UNKNOWN,
     MONO,
     STEREO,
+    DUALMONO,
 }
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecCapabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecCapabilities.aidl
index 9fcdf1c..641e2d6 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecCapabilities.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecCapabilities.aidl
@@ -17,11 +17,12 @@
 package android.hardware.bluetooth.audio;
 
 import android.hardware.bluetooth.audio.AacCapabilities;
-import android.hardware.bluetooth.audio.AptxCapabilities;
 import android.hardware.bluetooth.audio.AptxAdaptiveCapabilities;
+import android.hardware.bluetooth.audio.AptxCapabilities;
 import android.hardware.bluetooth.audio.CodecType;
 import android.hardware.bluetooth.audio.Lc3Capabilities;
 import android.hardware.bluetooth.audio.LdacCapabilities;
+import android.hardware.bluetooth.audio.OpusCapabilities;
 import android.hardware.bluetooth.audio.SbcCapabilities;
 
 /**
@@ -43,6 +44,7 @@
         AptxAdaptiveCapabilities aptxAdaptiveCapabilities;
         Lc3Capabilities lc3Capabilities;
         VendorCapabilities vendorCapabilities;
+        @nullable OpusCapabilities opusCapabilities;
     }
     CodecType codecType;
     Capabilities capabilities;
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecConfiguration.aidl
index 5ed12e3..8f7e419 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecConfiguration.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecConfiguration.aidl
@@ -17,11 +17,12 @@
 package android.hardware.bluetooth.audio;
 
 import android.hardware.bluetooth.audio.AacConfiguration;
-import android.hardware.bluetooth.audio.AptxConfiguration;
 import android.hardware.bluetooth.audio.AptxAdaptiveConfiguration;
+import android.hardware.bluetooth.audio.AptxConfiguration;
 import android.hardware.bluetooth.audio.CodecType;
 import android.hardware.bluetooth.audio.Lc3Configuration;
 import android.hardware.bluetooth.audio.LdacConfiguration;
+import android.hardware.bluetooth.audio.OpusConfiguration;
 import android.hardware.bluetooth.audio.SbcConfiguration;
 
 /**
@@ -45,6 +46,7 @@
         AptxAdaptiveConfiguration aptxAdaptiveConfig;
         Lc3Configuration lc3Config;
         VendorConfiguration vendorConfig;
+        @nullable OpusConfiguration opusConfig;
     }
     CodecType codecType;
     /**
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecType.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecType.aidl
index 386876e..3499155 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecType.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecType.aidl
@@ -28,4 +28,5 @@
     LC3,
     VENDOR,
     APTX_ADAPTIVE,
+    OPUS,
 }
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/OpusCapabilities.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/OpusCapabilities.aidl
new file mode 100644
index 0000000..5f05b3c
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/OpusCapabilities.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.ChannelMode;
+
+/**
+ * Used for Hardware Encoding/Decoding Opus codec capabilities.
+ */
+@VintfStability
+parcelable OpusCapabilities {
+    /*
+     * PCM is Input for encoder, Output for decoder
+     */
+    byte[] pcmBitDepth;
+    /*
+     * codec-specific parameters
+     */
+    int[] samplingFrequencyHz;
+    /*
+     * FrameDuration based on microseconds.
+     */
+    int[] frameDurationUs;
+    /*
+     * length in octets of a codec frame
+     */
+    int[] octetsPerFrame;
+    /*
+     * Number of blocks of codec frames per single SDU (Service Data Unit)
+     */
+    byte[] blocksPerSdu;
+    /*
+     * Channel mode used in A2DP special audio, ignored in standard LE Audio mode
+     */
+    ChannelMode[] channelMode;
+}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/OpusConfiguration.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/OpusConfiguration.aidl
new file mode 100644
index 0000000..6d35a54
--- /dev/null
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/OpusConfiguration.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.bluetooth.audio;
+
+import android.hardware.bluetooth.audio.ChannelMode;
+
+/**
+ * Used for Hardware Encoding/Decoding Opus codec configuration.
+ */
+@VintfStability
+parcelable OpusConfiguration {
+    /*
+     * PCM is Input for encoder, Output for decoder
+     */
+    byte pcmBitDepth;
+    /*
+     * codec-specific parameters
+     */
+    int samplingFrequencyHz;
+    /*
+     * FrameDuration based on microseconds.
+     */
+    int frameDurationUs;
+    /*
+     * length in octets of a codec frame
+     */
+    int octetsPerFrame;
+    /*
+     * Number of blocks of codec frames per single SDU (Service Data Unit)
+     */
+    byte blocksPerSdu;
+    /*
+     * Channel mode used in A2DP special audio, ignored in standard LE Audio mode
+     */
+    ChannelMode channelMode;
+}
diff --git a/bluetooth/audio/aidl/default/Android.bp b/bluetooth/audio/aidl/default/Android.bp
index 13a5440..cbf23dc 100644
--- a/bluetooth/audio/aidl/default/Android.bp
+++ b/bluetooth/audio/aidl/default/Android.bp
@@ -29,7 +29,7 @@
         "libcutils",
         "libfmq",
         "liblog",
-        "android.hardware.bluetooth.audio-V1-ndk",
+        "android.hardware.bluetooth.audio-V2-ndk",
         "libbluetooth_audio_session_aidl",
     ],
 }
diff --git a/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
index 911c928..c16ff54 100644
--- a/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
@@ -91,17 +91,21 @@
   else if (session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH)
     buffer_modifier = kBufferInCount;
 
+  // 24 bit audio stream is sent as unpacked
+  int bytes_per_sample =
+      (pcm_config.bitsPerSample == 24) ? 4 : (pcm_config.bitsPerSample / 8);
+
   uint32_t data_mq_size =
       (ceil(pcm_config.sampleRateHz) / 1000) *
-      channel_mode_to_channel_count(pcm_config.channelMode) *
-      (pcm_config.bitsPerSample / 8) * (pcm_config.dataIntervalUs / 1000) *
-      buffer_modifier;
+      channel_mode_to_channel_count(pcm_config.channelMode) * bytes_per_sample *
+      (pcm_config.dataIntervalUs / 1000) * buffer_modifier;
   if (data_mq_size <= 0) {
     LOG(ERROR) << __func__ << "Unexpected audio buffer size: " << data_mq_size
                << ", SampleRateHz: " << pcm_config.sampleRateHz
                << ", ChannelMode: " << toString(pcm_config.channelMode)
                << ", BitsPerSample: "
                << static_cast<int>(pcm_config.bitsPerSample)
+               << ", BytesPerSample: " << bytes_per_sample
                << ", DataIntervalUs: " << pcm_config.dataIntervalUs
                << ", SessionType: " << toString(session_type_);
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
diff --git a/bluetooth/audio/aidl/default/bluetooth_audio.xml b/bluetooth/audio/aidl/default/bluetooth_audio.xml
index 1859a1a..c4b1872 100644
--- a/bluetooth/audio/aidl/default/bluetooth_audio.xml
+++ b/bluetooth/audio/aidl/default/bluetooth_audio.xml
@@ -1,6 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.bluetooth.audio</name>
+        <version>2</version>
         <fqname>IBluetoothAudioProviderFactory/default</fqname>
     </hal>
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/bluetooth/audio/aidl/vts/Android.bp b/bluetooth/audio/aidl/vts/Android.bp
index feb952e..3aed1b3 100644
--- a/bluetooth/audio/aidl/vts/Android.bp
+++ b/bluetooth/audio/aidl/vts/Android.bp
@@ -17,7 +17,7 @@
     srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
     shared_libs: [
         "android.hardware.audio.common-V1-ndk",
-        "android.hardware.bluetooth.audio-V1-ndk",
+        "android.hardware.bluetooth.audio-V2-ndk",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
         "libbase",
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
index b599365..ebd728d 100644
--- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -57,6 +57,8 @@
     LeAudioCodecCapabilitiesSetting;
 using aidl::android::hardware::bluetooth::audio::LeAudioCodecConfiguration;
 using aidl::android::hardware::bluetooth::audio::LeAudioConfiguration;
+using aidl::android::hardware::bluetooth::audio::OpusCapabilities;
+using aidl::android::hardware::bluetooth::audio::OpusConfiguration;
 using aidl::android::hardware::bluetooth::audio::PcmConfiguration;
 using aidl::android::hardware::bluetooth::audio::PresentationPosition;
 using aidl::android::hardware::bluetooth::audio::SbcAllocMethod;
@@ -121,9 +123,9 @@
       dst.set<CodecConfiguration::CodecSpecific::aptxConfig>(
           src.get<CodecConfiguration::CodecSpecific::aptxConfig>());
       break;
-    case CodecConfiguration::CodecSpecific::lc3Config:
-      dst.set<CodecConfiguration::CodecSpecific::lc3Config>(
-          src.get<CodecConfiguration::CodecSpecific::lc3Config>());
+    case CodecConfiguration::CodecSpecific::opusConfig:
+      dst.set<CodecConfiguration::CodecSpecific::opusConfig>(
+          src.get<CodecConfiguration::CodecSpecific::opusConfig>());
       break;
     case CodecConfiguration::CodecSpecific::aptxAdaptiveConfig:
       dst.set<CodecConfiguration::CodecSpecific::aptxAdaptiveConfig>(
@@ -230,11 +232,12 @@
               ASSERT_EQ(codec_capabilities.capabilities.getTag(),
                         CodecCapabilities::Capabilities::ldacCapabilities);
               break;
-            case CodecType::LC3:
+            case CodecType::OPUS:
               ASSERT_EQ(codec_capabilities.capabilities.getTag(),
-                        CodecCapabilities::Capabilities::lc3Capabilities);
+                        CodecCapabilities::Capabilities::opusCapabilities);
               break;
             case CodecType::APTX_ADAPTIVE:
+            case CodecType::LC3:
             case CodecType::VENDOR:
             case CodecType::UNKNOWN:
               break;
@@ -484,39 +487,40 @@
   }
 
   std::vector<CodecConfiguration::CodecSpecific>
-  GetLc3CodecSpecificSupportedList(bool supported) {
-    std::vector<CodecConfiguration::CodecSpecific> lc3_codec_specifics;
+  GetOpusCodecSpecificSupportedList(bool supported) {
+    std::vector<CodecConfiguration::CodecSpecific> opus_codec_specifics;
     if (!supported) {
-      Lc3Configuration lc3_config{.samplingFrequencyHz = 0,
-                                  .frameDurationUs = 0};
-      lc3_codec_specifics.push_back(
-          CodecConfiguration::CodecSpecific(lc3_config));
-      return lc3_codec_specifics;
+      OpusConfiguration opus_config{.samplingFrequencyHz = 0,
+                                    .frameDurationUs = 0};
+      opus_codec_specifics.push_back(
+          CodecConfiguration::CodecSpecific(opus_config));
+      return opus_codec_specifics;
     }
-    GetA2dpOffloadCapabilityHelper(CodecType::LC3);
+    GetA2dpOffloadCapabilityHelper(CodecType::OPUS);
     if (temp_codec_capabilities_ == nullptr ||
-        temp_codec_capabilities_->codecType != CodecType::LC3) {
-      return lc3_codec_specifics;
+        temp_codec_capabilities_->codecType != CodecType::OPUS) {
+      return opus_codec_specifics;
     }
     // parse the capability
-    auto& lc3_capability =
+    auto& opus_capability =
         temp_codec_capabilities_->capabilities
-            .get<CodecCapabilities::Capabilities::lc3Capabilities>();
+            .get<CodecCapabilities::Capabilities::opusCapabilities>();
 
     // combine those parameters into one list of
     // CodecConfiguration::CodecSpecific
-    for (int32_t samplingFrequencyHz : lc3_capability.samplingFrequencyHz) {
-      for (int32_t frameDurationUs : lc3_capability.frameDurationUs) {
-        for (auto channel_mode : lc3_capability.channelMode) {
-          Lc3Configuration lc3_data{.samplingFrequencyHz = samplingFrequencyHz,
-                                    .channelMode = channel_mode,
-                                    .frameDurationUs = frameDurationUs};
-          lc3_codec_specifics.push_back(
-              CodecConfiguration::CodecSpecific(lc3_data));
+    for (int32_t samplingFrequencyHz : opus_capability->samplingFrequencyHz) {
+      for (int32_t frameDurationUs : opus_capability->frameDurationUs) {
+        for (auto channel_mode : opus_capability->channelMode) {
+          OpusConfiguration opus_data{
+              .samplingFrequencyHz = samplingFrequencyHz,
+              .channelMode = channel_mode,
+              .frameDurationUs = frameDurationUs};
+          opus_codec_specifics.push_back(
+              CodecConfiguration::CodecSpecific(opus_data));
         }
       }
     }
-    return lc3_codec_specifics;
+    return opus_codec_specifics;
   }
 
   bool IsPcmConfigSupported(const PcmConfiguration& pcm_config) {
@@ -762,23 +766,23 @@
 /**
  * Test whether each provider of type
  * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
- * LDAC hardware encoding config
+ * Opus hardware encoding config
  */
 TEST_P(BluetoothAudioProviderA2dpEncodingHardwareAidl,
-       StartAndEndA2dpLc3EncodingHardwareSession) {
+       StartAndEndA2dpOpusEncodingHardwareSession) {
   if (!IsOffloadSupported()) {
     return;
   }
 
   CodecConfiguration codec_config = {
-      .codecType = CodecType::LC3,
+      .codecType = CodecType::OPUS,
       .encodedAudioBitrate = 990000,
       .peerMtu = 1005,
       .isScmstEnabled = false,
   };
-  auto lc3_codec_specifics = GetLc3CodecSpecificSupportedList(true);
+  auto opus_codec_specifics = GetOpusCodecSpecificSupportedList(true);
 
-  for (auto& codec_specific : lc3_codec_specifics) {
+  for (auto& codec_specific : opus_codec_specifics) {
     copy_codec_specific(codec_config.config, codec_specific);
     DataMQDesc mq_desc;
     auto aidl_retval = audio_provider_->startSession(
@@ -855,10 +859,11 @@
       case CodecType::APTX_HD:
         codec_specifics = GetAptxCodecSpecificSupportedList(true, false);
         break;
-      case CodecType::LC3:
-        codec_specifics = GetLc3CodecSpecificSupportedList(false);
+      case CodecType::OPUS:
+        codec_specifics = GetOpusCodecSpecificSupportedList(false);
         continue;
       case CodecType::APTX_ADAPTIVE:
+      case CodecType::LC3:
       case CodecType::VENDOR:
       case CodecType::UNKNOWN:
         codec_specifics.clear();
@@ -1788,23 +1793,23 @@
 /**
  * Test whether each provider of type
  * SessionType::A2DP_HARDWARE_DECODING_DATAPATH can be started and stopped with
- * LDAC hardware encoding config
+ * Opus hardware encoding config
  */
 TEST_P(BluetoothAudioProviderA2dpDecodingHardwareAidl,
-       StartAndEndA2dpLc3DecodingHardwareSession) {
+       StartAndEndA2dpOpusDecodingHardwareSession) {
   if (!IsOffloadSupported()) {
     return;
   }
 
   CodecConfiguration codec_config = {
-      .codecType = CodecType::LC3,
+      .codecType = CodecType::OPUS,
       .encodedAudioBitrate = 990000,
       .peerMtu = 1005,
       .isScmstEnabled = false,
   };
-  auto lc3_codec_specifics = GetLc3CodecSpecificSupportedList(true);
+  auto opus_codec_specifics = GetOpusCodecSpecificSupportedList(true);
 
-  for (auto& codec_specific : lc3_codec_specifics) {
+  for (auto& codec_specific : opus_codec_specifics) {
     copy_codec_specific(codec_config.config, codec_specific);
     DataMQDesc mq_desc;
     auto aidl_retval = audio_provider_->startSession(
@@ -1881,10 +1886,11 @@
       case CodecType::APTX_HD:
         codec_specifics = GetAptxCodecSpecificSupportedList(true, false);
         break;
-      case CodecType::LC3:
-        codec_specifics = GetLc3CodecSpecificSupportedList(false);
+      case CodecType::OPUS:
+        codec_specifics = GetOpusCodecSpecificSupportedList(false);
         continue;
       case CodecType::APTX_ADAPTIVE:
+      case CodecType::LC3:
       case CodecType::VENDOR:
       case CodecType::UNKNOWN:
         codec_specifics.clear();
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index 42f9455..d08cb0a 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -51,7 +51,7 @@
         "libbinder_ndk",
         "libfmq",
         "liblog",
-        "android.hardware.bluetooth.audio-V1-ndk",
+        "android.hardware.bluetooth.audio-V2-ndk",
         "libhidlbase",
     ],
 }
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
index f3ca279..b858f50 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -26,6 +26,8 @@
 #include <aidl/android/hardware/bluetooth/audio/LdacChannelMode.h>
 #include <aidl/android/hardware/bluetooth/audio/LdacQualityIndex.h>
 #include <aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/OpusCapabilities.h>
+#include <aidl/android/hardware/bluetooth/audio/OpusConfiguration.h>
 #include <aidl/android/hardware/bluetooth/audio/SbcCapabilities.h>
 #include <aidl/android/hardware/bluetooth/audio/SbcChannelMode.h>
 #include <android-base/logging.h>
@@ -37,7 +39,7 @@
 namespace audio {
 
 static const PcmCapabilities kDefaultSoftwarePcmCapabilities = {
-    .sampleRateHz = {16000, 24000, 44100, 48000, 88200, 96000},
+    .sampleRateHz = {16000, 24000, 32000, 44100, 48000, 88200, 96000},
     .channelMode = {ChannelMode::MONO, ChannelMode::STEREO},
     .bitsPerSample = {16, 24, 32},
     .dataIntervalUs = {},
@@ -78,9 +80,9 @@
     .bitsPerSample = {24},
 };
 
-static const Lc3Capabilities kDefaultA2dpOffloadLc3Capability = {
-    .samplingFrequencyHz = {44100, 48000},
-    .frameDurationUs = {7500, 10000},
+static const OpusCapabilities kDefaultOffloadOpusCapability = {
+    .samplingFrequencyHz = {48000},
+    .frameDurationUs = {10000, 20000},
     .channelMode = {ChannelMode::MONO, ChannelMode::STEREO},
 };
 
@@ -90,7 +92,7 @@
     {.codecType = CodecType::LDAC, .capabilities = {}},
     {.codecType = CodecType::APTX, .capabilities = {}},
     {.codecType = CodecType::APTX_HD, .capabilities = {}},
-    {.codecType = CodecType::LC3, .capabilities = {}}};
+    {.codecType = CodecType::OPUS, .capabilities = {}}};
 
 std::vector<LeAudioCodecCapabilitiesSetting> kDefaultOffloadLeAudioCapabilities;
 
@@ -294,22 +296,24 @@
   return false;
 }
 
-bool BluetoothAudioCodecs::IsOffloadLc3ConfigurationValid(
+bool BluetoothAudioCodecs::IsOffloadOpusConfigurationValid(
     const CodecConfiguration::CodecSpecific& codec_specific) {
-  if (codec_specific.getTag() != CodecConfiguration::CodecSpecific::lc3Config) {
+  if (codec_specific.getTag() !=
+      CodecConfiguration::CodecSpecific::opusConfig) {
     LOG(WARNING) << __func__
                  << ": Invalid CodecSpecific=" << codec_specific.toString();
     return false;
   }
-  const Lc3Configuration lc3_data =
-      codec_specific.get<CodecConfiguration::CodecSpecific::lc3Config>();
+  std::optional<OpusConfiguration> opus_data =
+      codec_specific.get<CodecConfiguration::CodecSpecific::opusConfig>();
 
-  if (ContainedInVector(kDefaultA2dpOffloadLc3Capability.samplingFrequencyHz,
-                        lc3_data.samplingFrequencyHz) &&
-      ContainedInVector(kDefaultA2dpOffloadLc3Capability.frameDurationUs,
-                        lc3_data.frameDurationUs) &&
-      ContainedInVector(kDefaultA2dpOffloadLc3Capability.channelMode,
-                        lc3_data.channelMode)) {
+  if (opus_data.has_value() &&
+      ContainedInVector(kDefaultOffloadOpusCapability.samplingFrequencyHz,
+                        opus_data->samplingFrequencyHz) &&
+      ContainedInVector(kDefaultOffloadOpusCapability.frameDurationUs,
+                        opus_data->frameDurationUs) &&
+      ContainedInVector(kDefaultOffloadOpusCapability.channelMode,
+                        opus_data->channelMode)) {
     return true;
   }
   LOG(WARNING) << __func__
@@ -371,13 +375,14 @@
             .set<CodecCapabilities::Capabilities::aptxCapabilities>(
                 kDefaultOffloadAptxHdCapability);
         break;
-      case CodecType::LC3:
+      case CodecType::OPUS:
         codec_capability.capabilities
-            .set<CodecCapabilities::Capabilities::lc3Capabilities>(
-                kDefaultA2dpOffloadLc3Capability);
+            .set<CodecCapabilities::Capabilities::opusCapabilities>(
+                kDefaultOffloadOpusCapability);
         break;
       case CodecType::UNKNOWN:
       case CodecType::VENDOR:
+      case CodecType::LC3:
       case CodecType::APTX_ADAPTIVE:
         break;
     }
@@ -438,12 +443,13 @@
         return true;
       }
       break;
-    case CodecType::LC3:
-      if (IsOffloadLc3ConfigurationValid(codec_specific)) {
+    case CodecType::OPUS:
+      if (IsOffloadOpusConfigurationValid(codec_specific)) {
         return true;
       }
       break;
     case CodecType::APTX_ADAPTIVE:
+    case CodecType::LC3:
     case CodecType::UNKNOWN:
     case CodecType::VENDOR:
       break;
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
index 0259a7e..ed0598b 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.h
@@ -18,9 +18,9 @@
 
 #include <aidl/android/hardware/bluetooth/audio/CodecCapabilities.h>
 #include <aidl/android/hardware/bluetooth/audio/CodecConfiguration.h>
-#include <aidl/android/hardware/bluetooth/audio/Lc3Configuration.h>
 #include <aidl/android/hardware/bluetooth/audio/LeAudioCodecCapabilitiesSetting.h>
 #include <aidl/android/hardware/bluetooth/audio/LeAudioConfiguration.h>
+#include <aidl/android/hardware/bluetooth/audio/OpusConfiguration.h>
 #include <aidl/android/hardware/bluetooth/audio/PcmCapabilities.h>
 #include <aidl/android/hardware/bluetooth/audio/PcmConfiguration.h>
 #include <aidl/android/hardware/bluetooth/audio/SessionType.h>
@@ -71,7 +71,7 @@
       const CodecConfiguration::CodecSpecific& codec_specific);
   static bool IsOffloadAptxHdConfigurationValid(
       const CodecConfiguration::CodecSpecific& codec_specific);
-  static bool IsOffloadLc3ConfigurationValid(
+  static bool IsOffloadOpusConfigurationValid(
       const CodecConfiguration::CodecSpecific& codec_specific);
 };
 
diff --git a/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h b/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h
index ac17d6d..572a8b6 100644
--- a/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h
+++ b/boot/1.1/default/boot_control/include/libboot_control/libboot_control.h
@@ -25,9 +25,8 @@
 
 // Helper library to implement the IBootControl HAL using the misc partition.
 class BootControl {
-  using MergeStatus = ::android::hardware::boot::V1_1::MergeStatus;
-
  public:
+  using MergeStatus = ::android::hardware::boot::V1_1::MergeStatus;
   bool Init();
   unsigned int GetNumberSlots();
   unsigned int GetCurrentSlot();
diff --git a/boot/1.1/default/boot_control/include/private/boot_control_definition.h b/boot/1.1/default/boot_control/include/private/boot_control_definition.h
index 8f02111..57c2f73 100644
--- a/boot/1.1/default/boot_control/include/private/boot_control_definition.h
+++ b/boot/1.1/default/boot_control/include/private/boot_control_definition.h
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#include <stdint.h>
+
+#include <bootloader_message/bootloader_message.h>
 
 /**
  * The A/B-specific bootloader message structure (4-KiB).
diff --git a/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp b/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp
index c38f257..05f136e 100644
--- a/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp
+++ b/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp
@@ -1,4 +1,5 @@
 /*
+
  * Copyright (C) 2019 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,6 +20,7 @@
 #include <vector>
 
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android/hardware/boot/1.1/IBootControl.h>
 #include <android/hardware/boot/1.1/types.h>
 #include <gmock/gmock.h>
@@ -37,9 +39,21 @@
 using ::android::hardware::boot::V1_1::MergeStatus;
 using ::testing::Contains;
 
+bool IsVirtualAbEnabled();
+
+#define SKIP_IF_NON_VIRTUAL_AB()                                                        \
+    do {                                                                                \
+        if (!IsVirtualAbEnabled()) GTEST_SKIP() << "Test for Virtual A/B devices only"; \
+    } while (0)
+
+bool IsVirtualAbEnabled() {
+    return android::base::GetBoolProperty("ro.virtual_ab.enabled", false);
+}
+
 class BootHidlTest : public testing::TestWithParam<std::string> {
   public:
     virtual void SetUp() override {
+        SKIP_IF_NON_VIRTUAL_AB();
         boot = IBootControl::getService(GetParam());
         ASSERT_NE(boot, nullptr);
 
diff --git a/boot/aidl/Android.bp b/boot/aidl/Android.bp
new file mode 100644
index 0000000..be38245
--- /dev/null
+++ b/boot/aidl/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.boot",
+    vendor_available: true,
+    srcs: ["android/hardware/boot/*.aidl"],
+    stability: "vintf",
+    recovery_available: true,
+    backend: {
+        java: {
+            sdk_version: "module_current",
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+}
diff --git a/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/IBootControl.aidl b/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/IBootControl.aidl
new file mode 100644
index 0000000..c8ab51e
--- /dev/null
+++ b/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/IBootControl.aidl
@@ -0,0 +1,50 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.boot;
+@VintfStability
+interface IBootControl {
+  int getActiveBootSlot();
+  int getCurrentSlot();
+  int getNumberSlots();
+  android.hardware.boot.MergeStatus getSnapshotMergeStatus();
+  String getSuffix(in int slot);
+  boolean isSlotBootable(in int slot);
+  boolean isSlotMarkedSuccessful(in int slot);
+  void markBootSuccessful();
+  void setActiveBootSlot(in int slot);
+  void setSlotAsUnbootable(in int slot);
+  void setSnapshotMergeStatus(in android.hardware.boot.MergeStatus status);
+  const int INVALID_SLOT = -1;
+  const int COMMAND_FAILED = -2;
+}
diff --git a/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/MergeStatus.aidl b/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/MergeStatus.aidl
new file mode 100644
index 0000000..53c6204
--- /dev/null
+++ b/boot/aidl/aidl_api/android.hardware.boot/current/android/hardware/boot/MergeStatus.aidl
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.boot;
+@Backing(type="int") @VintfStability
+enum MergeStatus {
+  NONE = 0,
+  UNKNOWN = 1,
+  SNAPSHOTTED = 2,
+  MERGING = 3,
+  CANCELLED = 4,
+}
diff --git a/boot/aidl/android/hardware/boot/IBootControl.aidl b/boot/aidl/android/hardware/boot/IBootControl.aidl
new file mode 100644
index 0000000..6c9e8ce
--- /dev/null
+++ b/boot/aidl/android/hardware/boot/IBootControl.aidl
@@ -0,0 +1,158 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package android.hardware.boot;
+
+import android.hardware.boot.MergeStatus;
+
+@VintfStability
+interface IBootControl {
+    const int INVALID_SLOT = -1;
+    const int COMMAND_FAILED = -2;
+    /**
+     * Returns the active slot to boot into on the next boot. If
+     * setActiveBootSlot() has been called, the getter function should return the
+     * same slot as the one provided in the last setActiveBootSlot() call.
+     * The returned value is always guaranteed to be strictly less than the
+     * value returned by getNumberSlots. Slots start at 0 and finish at
+     * getNumberSlots() - 1. For instance, a system with A/B must return 0 or 1.
+     * @return the active slot to boot into on the next boot.
+     */
+    int getActiveBootSlot();
+
+    /**
+     * getCurrentSlot() returns the slot number of that the current boot is booted
+     * from, for example slot number 0 (Slot A). It is assumed that if the current
+     * slot is A, then the block devices underlying B can be accessed directly
+     * without any risk of corruption.
+     * The returned value is always guaranteed to be strictly less than the
+     * value returned by getNumberSlots. Slots start at 0 and finish at
+     * getNumberSlots() - 1. The value returned here must match the suffix passed
+     * from the bootloader, regardless of which slot is active or successful.
+     * @return the slot number of that the current boot is booted
+     */
+    int getCurrentSlot();
+
+    /**
+     * getNumberSlots() returns the number of available slots.
+     * For instance, a system with a single set of partitions must return
+     * 1, a system with A/B must return 2, A/B/C -> 3 and so on. A system with
+     * less than two slots doesn't support background updates, for example if
+     * running from a virtual machine with only one copy of each partition for the
+     * purpose of testing.
+     * @return number of available slots
+     */
+    int getNumberSlots();
+
+    /**
+     * Returns whether a snapshot-merge of any dynamic partition is in progress.
+     *
+     * This function must return the merge status set by the last setSnapshotMergeStatus call and
+     * recorded by the bootloader with one exception. If the partitions are being flashed from the
+     * bootloader such that the pending merge must be canceled (for example, if the super partition
+     * is being flashed), this function must return CANCELLED.
+     *
+     * @param out success True if the merge status is read successfully, false otherwise.
+     * @return Merge status.
+     */
+    MergeStatus getSnapshotMergeStatus();
+
+    /**
+     * getSuffix() returns the string suffix used by partitions that correspond to
+     * the slot number passed in as a parameter. The bootloader must pass the
+     * suffix of the currently active slot either through a kernel command line
+     * property at androidboot.slot_suffix, or the device tree at
+     * /firmware/android/slot_suffix.
+     * @return suffix for the input slot, or the empty string "" if slot
+     * does not match an existing slot.
+     */
+    String getSuffix(in int slot);
+
+    /**
+     * isSlotBootable() returns if the slot passed in parameter is bootable. Note
+     * that slots can be made unbootable by both the bootloader and by the OS
+     * using setSlotAsUnbootable.
+     * @return true if the slot is bootable, false if it's not.
+     * @throws service specific error INVALID_SLOT if slot is invalid.
+     */
+    boolean isSlotBootable(in int slot);
+
+    /**
+     * isSlotMarkedSuccessful() returns if the slot passed in parameter has been
+     * marked as successful using markBootSuccessful. Note that only the current
+     * slot can be marked as successful but any slot can be queried.
+     * @return true if the slot has been marked as successful, false if it has
+     * not.
+     * @throws service specific error INVALID_SLOT if slot is invalid.
+     */
+    boolean isSlotMarkedSuccessful(in int slot);
+
+    /**
+     * markBootSuccessful() marks the current slot as having booted successfully.
+     *
+     * @throws Service specific error COMMAND_FAILED if command failed.
+     */
+    void markBootSuccessful();
+
+    /**
+     * setActiveBootSlot() marks the slot passed in parameter as the active boot
+     * slot (see getCurrentSlot for an explanation of the "slot" parameter). This
+     * overrides any previous call to setSlotAsUnbootable.
+     * @throws Service specific error INVALID_SLOT if slot is invalid, or COMMAND_FAILED if
+     * operation failed.
+     */
+    void setActiveBootSlot(in int slot);
+
+    /**
+     * setSlotAsUnbootable() marks the slot passed in parameter as
+     * an unbootable. This can be used while updating the contents of the slot's
+     * partitions, so that the system must not attempt to boot a known bad set up.
+     * @throws Service specific error INVALID_SLOT if slot is invalid, or COMMAND_FAILED if
+     * operation failed.
+     */
+    void setSlotAsUnbootable(in int slot);
+
+    /**
+     * Sets whether a snapshot-merge of any dynamic partition is in progress.
+     *
+     * After the merge status is set to a given value, subsequent calls to
+     * getSnapshotMergeStatus must return the set value.
+     *
+     * The merge status must be persistent across reboots. That is, getSnapshotMergeStatus
+     * must return the same value after a reboot if the merge status is not altered in any way
+     * (e.g. set by setSnapshotMergeStatus or set to CANCELLED by bootloader).
+     *
+     * Read/write access to the merge status must be atomic. When the HAL is processing a
+     * setSnapshotMergeStatus call, all subsequent calls to getSnapshotMergeStatus must block until
+     * setSnapshotMergeStatus has returned.
+     *
+     * A MERGING state indicates that dynamic partitions are partially comprised by blocks in the
+     * userdata partition.
+     *
+     * When the merge status is set to MERGING, the following operations must be prohibited from the
+     * bootloader:
+     *  - Flashing or erasing "userdata" or "metadata".
+     *
+     * The following operations may be prohibited when the status is set to MERGING. If not
+     * prohibited, it is recommended that the user receive a warning.
+     *  - Changing the active slot (e.g. via "fastboot set_active")
+     *
+     * @param status Merge status.
+     *
+     * @throws service specific error COMMAND_FAILED if operation failed.
+     */
+    void setSnapshotMergeStatus(in MergeStatus status);
+}
diff --git a/boot/aidl/android/hardware/boot/MergeStatus.aidl b/boot/aidl/android/hardware/boot/MergeStatus.aidl
new file mode 100644
index 0000000..16ac85f
--- /dev/null
+++ b/boot/aidl/android/hardware/boot/MergeStatus.aidl
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package android.hardware.boot;
+
+@VintfStability
+@Backing(type="int")
+enum MergeStatus {
+    /**
+     * No snapshot or merge is in progress.
+     */
+    NONE = 0,
+    /**
+     * The merge status could not be determined.
+     */
+    UNKNOWN,
+    /**
+     * Partitions are being snapshotted, but no merge has been started.
+     */
+    SNAPSHOTTED,
+    /**
+     * At least one partition has merge is in progress.
+     */
+    MERGING,
+    /**
+     * A merge was in progress, but it was canceled by the bootloader.
+     */
+    CANCELLED,
+}
diff --git a/boot/aidl/client/Android.bp b/boot/aidl/client/Android.bp
new file mode 100644
index 0000000..db4a7ea
--- /dev/null
+++ b/boot/aidl/client/Android.bp
@@ -0,0 +1,31 @@
+
+
+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: "libboot_control_client",
+    srcs: [
+        "BootControlClient.cpp"
+    ],
+    export_include_dirs: ["include"],
+    export_shared_lib_headers: ["android.hardware.boot-V1-ndk"],
+    recovery_available: true,
+    shared_libs: [
+        "android.hardware.boot-V1-ndk",
+        "android.hardware.boot@1.0",
+        "android.hardware.boot@1.1",
+        "android.hardware.boot@1.2",
+        "libhidlbase",
+        "libbinder_ndk",
+        "libbase",
+        "libcutils",
+        "libutils",
+    ],
+}
diff --git a/boot/aidl/client/BootControlClient.cpp b/boot/aidl/client/BootControlClient.cpp
new file mode 100644
index 0000000..89258d2
--- /dev/null
+++ b/boot/aidl/client/BootControlClient.cpp
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <BootControlClient.h>
+
+#include <aidl/android/hardware/boot/IBootControl.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/hardware/boot/1.0/IBootControl.h>
+#include <android/hardware/boot/1.1/IBootControl.h>
+#include <android/hardware/boot/1.2/IBootControl.h>
+#include "utils/StrongPointer.h"
+
+#define CONCAT(x, y) x##y
+
+#define LOG_NDK_STATUS(x)                                                                   \
+    do {                                                                                    \
+        const auto CONCAT(status, __COUNTER__) = x;                                         \
+        if (!CONCAT(status, __COUNTER__).isOk()) {                                          \
+            LOG(ERROR) << #x << " failed " << CONCAT(status, __COUNTER__).getDescription(); \
+        }                                                                                   \
+    } while (0)
+
+using aidl::android::hardware::boot::MergeStatus;
+
+std::ostream& operator<<(std::ostream& os, MergeStatus status) {
+    switch (status) {
+        case MergeStatus::NONE:
+            os << "MergeStatus::NONE";
+            break;
+        case MergeStatus::UNKNOWN:
+            os << "MergeStatus::UNKNOWN";
+            break;
+        case MergeStatus::SNAPSHOTTED:
+            os << "MergeStatus::SNAPSHOTTED";
+            break;
+        case MergeStatus::MERGING:
+            os << "MergeStatus::MERGING";
+            break;
+        case MergeStatus::CANCELLED:
+            os << "MergeStatus::CANCELLED";
+            break;
+        default:
+            os << static_cast<int>(status);
+            break;
+    }
+    return os;
+}
+
+namespace android::hal {
+class BootControlClientAidl final : public BootControlClient {
+    using IBootControl = ::aidl::android::hardware::boot::IBootControl;
+
+  public:
+    BootControlClientAidl(std::shared_ptr<IBootControl> module) : module_(module) {}
+
+    BootControlVersion GetVersion() const override { return BootControlVersion::BOOTCTL_AIDL; }
+
+    ~BootControlClientAidl() = default;
+    virtual int32_t GetNumSlots() const {
+        int32_t ret = -1;
+        LOG_NDK_STATUS(module_->getNumberSlots(&ret));
+        return ret;
+    }
+
+    int32_t GetCurrentSlot() const {
+        int32_t ret = -1;
+        LOG_NDK_STATUS(module_->getCurrentSlot(&ret));
+        return ret;
+    }
+    MergeStatus getSnapshotMergeStatus() const {
+        MergeStatus status = MergeStatus::UNKNOWN;
+        LOG_NDK_STATUS(module_->getSnapshotMergeStatus(&status));
+        return status;
+    }
+    std::string GetSuffix(int32_t slot) const {
+        std::string ret;
+        const auto status = module_->getSuffix(slot, &ret);
+        if (!status.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << status.getDescription();
+            return {};
+        }
+        return ret;
+    }
+
+    std::optional<bool> IsSlotBootable(int32_t slot) const {
+        bool ret = false;
+        const auto status = module_->isSlotBootable(slot, &ret);
+        if (!status.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << status.getDescription();
+            return {};
+        }
+        return ret;
+    }
+
+    CommandResult MarkSlotUnbootable(int32_t slot) {
+        const auto status = module_->setSlotAsUnbootable(slot);
+        if (!status.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << status.getDescription();
+        }
+        return {.success = status.isOk(), .errMsg = status.getDescription()};
+    }
+
+    CommandResult SetActiveBootSlot(int slot) {
+        const auto status = module_->setActiveBootSlot(slot);
+        if (!status.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << status.getDescription();
+        }
+        return {.success = status.isOk(), .errMsg = status.getDescription()};
+    }
+    int GetActiveBootSlot() const {
+        int ret = -1;
+        LOG_NDK_STATUS(module_->getActiveBootSlot(&ret));
+        return ret;
+    }
+
+    // Check if |slot| is marked boot successfully.
+    std::optional<bool> IsSlotMarkedSuccessful(int slot) const {
+        bool ret = false;
+        const auto status = module_->isSlotMarkedSuccessful(slot, &ret);
+        if (!status.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << status.getDescription();
+            return {};
+        }
+        return ret;
+    }
+
+    CommandResult MarkBootSuccessful() {
+        const auto status = module_->markBootSuccessful();
+        if (!status.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << " failed " << status.getDescription();
+        }
+        return {.success = status.isOk(), .errMsg = status.getDescription()};
+    }
+
+    CommandResult SetSnapshotMergeStatus(aidl::android::hardware::boot::MergeStatus merge_status) {
+        const auto status = module_->setSnapshotMergeStatus(merge_status);
+        if (!status.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << merge_status << ")"
+                       << " failed " << status.getDescription();
+        }
+        return {.success = status.isOk(), .errMsg = status.getDescription()};
+    }
+
+  private:
+    const std::shared_ptr<IBootControl> module_;
+};
+
+using namespace android::hardware::boot;
+
+class BootControlClientHIDL final : public BootControlClient {
+  public:
+    BootControlClientHIDL(android::sp<V1_0::IBootControl> module_v1,
+                          android::sp<V1_1::IBootControl> module_v1_1,
+                          android::sp<V1_2::IBootControl> module_v1_2)
+        : module_v1_(module_v1), module_v1_1_(module_v1_1), module_v1_2_(module_v1_2) {
+        CHECK(module_v1_ != nullptr);
+    }
+    BootControlVersion GetVersion() const override {
+        if (module_v1_2_ != nullptr) {
+            return BootControlVersion::BOOTCTL_V1_2;
+        } else if (module_v1_1_ != nullptr) {
+            return BootControlVersion::BOOTCTL_V1_1;
+        } else {
+            return BootControlVersion::BOOTCTL_V1_0;
+        }
+    }
+    int32_t GetNumSlots() const {
+        const auto ret = module_v1_->getNumberSlots();
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+        }
+        return ret.withDefault(-1);
+    }
+
+    int32_t GetCurrentSlot() const {
+        const auto ret = module_v1_->getCurrentSlot();
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+        }
+        return ret.withDefault(-1);
+    }
+
+    std::string GetSuffix(int32_t slot) const {
+        std::string suffix;
+        const auto ret = module_v1_->getSuffix(
+                slot,
+                [&](const ::android::hardware::hidl_string& slotSuffix) { suffix = slotSuffix; });
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << ret.description();
+        }
+        return suffix;
+    }
+
+    std::optional<bool> IsSlotBootable(int32_t slot) const {
+        const auto ret = module_v1_->isSlotBootable(slot);
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << ret.description();
+            return {};
+        }
+        const auto bool_result = ret.withDefault(V1_0::BoolResult::INVALID_SLOT);
+        if (bool_result == V1_0::BoolResult::INVALID_SLOT) {
+            return {};
+        }
+        return bool_result == V1_0::BoolResult::TRUE;
+    }
+
+    CommandResult MarkSlotUnbootable(int32_t slot) {
+        CommandResult result;
+        const auto ret =
+                module_v1_->setSlotAsUnbootable(slot, [&](const V1_0::CommandResult& error) {
+                    result.success = error.success;
+                    result.errMsg = error.errMsg;
+                });
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << ret.description();
+        }
+        return result;
+    }
+
+    CommandResult SetActiveBootSlot(int32_t slot) {
+        CommandResult result;
+        const auto ret = module_v1_->setActiveBootSlot(slot, [&](const V1_0::CommandResult& error) {
+            result.success = error.success;
+            result.errMsg = error.errMsg;
+        });
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << ret.description();
+        }
+        return result;
+    }
+
+    CommandResult MarkBootSuccessful() {
+        CommandResult result;
+        const auto ret = module_v1_->markBootSuccessful([&](const V1_0::CommandResult& error) {
+            result.success = error.success;
+            result.errMsg = error.errMsg;
+        });
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+        }
+        return result;
+    }
+
+    std::optional<bool> IsSlotMarkedSuccessful(int32_t slot) const {
+        const auto ret = module_v1_->isSlotMarkedSuccessful(slot);
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << slot << ")"
+                       << " failed " << ret.description();
+            return {};
+        }
+        const auto bool_result = ret.withDefault(V1_0::BoolResult::INVALID_SLOT);
+        if (bool_result == V1_0::BoolResult::INVALID_SLOT) {
+            return {};
+        }
+        return bool_result == V1_0::BoolResult::TRUE;
+    }
+
+    MergeStatus getSnapshotMergeStatus() const {
+        if (module_v1_1_ == nullptr) {
+            LOG(ERROR) << __FUNCTION__ << " is unsupported, requires at least boot v1.1";
+            return MergeStatus::UNKNOWN;
+        }
+        const auto ret = module_v1_1_->getSnapshotMergeStatus();
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+        }
+        return static_cast<MergeStatus>(
+                ret.withDefault(static_cast<V1_1::MergeStatus>(MergeStatus::UNKNOWN)));
+    }
+
+    CommandResult SetSnapshotMergeStatus(MergeStatus merge_status) {
+        if (module_v1_1_ == nullptr) {
+            return {.success = false,
+                    .errMsg = "setSnapshotMergeStatus is unsupported, requires at least boot v1.1"};
+        }
+        const auto ret =
+                module_v1_1_->setSnapshotMergeStatus(static_cast<V1_1::MergeStatus>(merge_status));
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << "(" << merge_status << ")"
+                       << " failed " << ret.description();
+        }
+        return {.success = ret.isOk(), .errMsg = ret.description()};
+    }
+
+    int32_t GetActiveBootSlot() const {
+        if (module_v1_2_ == nullptr) {
+            LOG(ERROR) << __FUNCTION__ << " is unsupported, requires at least boot v1.2";
+            return -1;
+        }
+        const auto ret = module_v1_2_->getActiveBootSlot();
+        if (!ret.isOk()) {
+            LOG(ERROR) << __FUNCTION__ << " failed " << ret.description();
+        }
+        return ret.withDefault(-1);
+    }
+
+  private:
+    android::sp<V1_0::IBootControl> module_v1_;
+    android::sp<V1_1::IBootControl> module_v1_1_;
+    android::sp<V1_2::IBootControl> module_v1_2_;
+};
+
+std::unique_ptr<BootControlClient> BootControlClient::WaitForService() {
+    const auto instance_name =
+            std::string(::aidl::android::hardware::boot::IBootControl::descriptor) + "/default";
+
+    if (AServiceManager_isDeclared(instance_name.c_str())) {
+        auto module = ::aidl::android::hardware::boot::IBootControl::fromBinder(
+                ndk::SpAIBinder(AServiceManager_waitForService(instance_name.c_str())));
+        if (module == nullptr) {
+            LOG(ERROR) << "AIDL " << instance_name
+                       << " is declared but waitForService returned nullptr.";
+            return nullptr;
+        }
+        LOG(INFO) << "Using AIDL version of IBootControl";
+        return std::make_unique<BootControlClientAidl>(module);
+    }
+    LOG(INFO) << "AIDL IBootControl not available, falling back to HIDL.";
+
+    android::sp<V1_0::IBootControl> v1_0_module;
+    android::sp<V1_1::IBootControl> v1_1_module;
+    android::sp<V1_2::IBootControl> v1_2_module;
+    v1_0_module = V1_0::IBootControl::getService();
+    if (v1_0_module == nullptr) {
+        LOG(ERROR) << "Error getting bootctrl v1.0 module.";
+        return nullptr;
+    }
+    v1_1_module = V1_1::IBootControl::castFrom(v1_0_module);
+    v1_2_module = V1_2::IBootControl::castFrom(v1_0_module);
+    if (v1_2_module != nullptr) {
+        LOG(INFO) << "Using HIDL version 1.2 of IBootControl";
+    } else if (v1_1_module != nullptr) {
+        LOG(INFO) << "Using HIDL version 1.1 of IBootControl";
+    } else {
+        LOG(INFO) << "Using HIDL version 1.0 of IBootControl";
+    }
+
+    return std::make_unique<BootControlClientHIDL>(v1_0_module, v1_1_module, v1_2_module);
+}
+
+}  // namespace android::hal
diff --git a/boot/aidl/client/include/BootControlClient.h b/boot/aidl/client/include/BootControlClient.h
new file mode 100644
index 0000000..472e82e
--- /dev/null
+++ b/boot/aidl/client/include/BootControlClient.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __BOOT_CONTROL_CLIENT_H_
+#define __BOOT_CONTROL_CLIENT_H_
+
+#include <aidl/android/hardware/boot/MergeStatus.h>
+
+#include <stdint.h>
+
+#include <memory>
+#include <optional>
+
+namespace android::hal {
+
+struct CommandResult {
+    bool success;
+    std::string errMsg;
+    constexpr bool IsOk() const { return success; }
+};
+
+enum class BootControlVersion { BOOTCTL_V1_0, BOOTCTL_V1_1, BOOTCTL_V1_2, BOOTCTL_AIDL };
+
+class BootControlClient {
+  public:
+    using MergeStatus = aidl::android::hardware::boot::MergeStatus;
+    virtual ~BootControlClient() = default;
+    virtual BootControlVersion GetVersion() const = 0;
+    // Return the number of update slots in the system. A system will normally
+    // have two slots, named "A" and "B" in the documentation, but sometimes
+    // images running from other media can have only one slot, like some USB
+    // image. Systems with only one slot won't be able to update.
+    [[nodiscard]] virtual int32_t GetNumSlots() const = 0;
+
+    // Return the slot where we are running the system from. On success, the
+    // result is a number between 0 and GetNumSlots() - 1. Otherwise, log an error
+    // and return kInvalidSlot.
+    [[nodiscard]] virtual int32_t GetCurrentSlot() const = 0;
+
+    // Return string suffix for input slot. Usually, for slot 0 the suffix is _a, and for slot 1 the
+    // suffix is _b.
+    [[nodiscard]] virtual std::string GetSuffix(int32_t slot) const = 0;
+
+    // Returns whether the passed |slot| is marked as bootable. Returns false if
+    // the slot is invalid.
+    [[nodiscard]] virtual std::optional<bool> IsSlotBootable(int32_t slot) const = 0;
+
+    // Mark the specified slot unbootable. No other slot flags are modified.
+    // Returns true on success.
+    [[nodiscard]] virtual CommandResult MarkSlotUnbootable(int32_t slot) = 0;
+
+    // Set the passed |slot| as the preferred boot slot. Returns whether it
+    // succeeded setting the active slot. If succeeded, on next boot the
+    // bootloader will attempt to load the |slot| marked as active. Note that this
+    // method doesn't change the value of GetCurrentSlot() on the current boot.
+    // Return true if operation succeeded.
+    [[nodiscard]] virtual CommandResult SetActiveBootSlot(int32_t slot) = 0;
+
+    // Check if |slot| is marked boot successfully. Return empty optional if the RPC call failed.
+    [[nodiscard]] virtual std::optional<bool> IsSlotMarkedSuccessful(int32_t slot) const = 0;
+
+    // Mark boot as successful. Return an error message if operation failed.
+    [[nodiscard]] virtual CommandResult MarkBootSuccessful() = 0;
+
+    // Added in IBootControl v1.1
+    // Return the current merge status.
+    [[nodiscard]] virtual MergeStatus getSnapshotMergeStatus() const = 0;
+
+    // Set snapshot merge status, return true if succeeded.
+    [[nodiscard]] virtual CommandResult SetSnapshotMergeStatus(MergeStatus status) = 0;
+
+    // Added in IBootControl v1.2
+    // Get the active slot. In other words, the slot which will be used on
+    // next system reboot. This should match the |slot| parameter of last
+    // successful call to |SetActiveBootSlot|.
+    // Return 0xFFFFFFFF if underlying HAL doesn't support this operation.
+    [[nodiscard]] virtual int32_t GetActiveBootSlot() const = 0;
+
+    [[nodiscard]] static std::unique_ptr<BootControlClient> WaitForService();
+};
+
+}  // namespace android::hal
+
+#endif
diff --git a/boot/aidl/default/Android.bp b/boot/aidl/default/Android.bp
new file mode 100644
index 0000000..6aefae8
--- /dev/null
+++ b/boot/aidl/default/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // 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_binary {
+    name: "android.hardware.boot-service.default",
+    defaults: ["libboot_control_defaults"],
+    relative_install_path: "hw",
+    init_rc: ["boot-default.rc"],
+    vintf_fragments: ["boot-default.xml"],
+    vendor: true,
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "android.hardware.boot@1.1",
+        "android.hardware.boot-V1-ndk",
+    ],
+    static_libs: [
+        "libboot_control",
+    ],
+    srcs: ["main.cpp", "BootControl.cpp"],
+}
diff --git a/boot/aidl/default/BootControl.cpp b/boot/aidl/default/BootControl.cpp
new file mode 100644
index 0000000..4e3c21b
--- /dev/null
+++ b/boot/aidl/default/BootControl.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BootControl.h"
+#include <cstdint>
+
+#include <android-base/logging.h>
+
+using HIDLMergeStatus = ::android::bootable::BootControl::MergeStatus;
+using ndk::ScopedAStatus;
+
+namespace aidl::android::hardware::boot {
+
+BootControl::BootControl() {
+    CHECK(impl_.Init());
+}
+
+ScopedAStatus BootControl::getActiveBootSlot(int32_t* _aidl_return) {
+    *_aidl_return = impl_.GetActiveBootSlot();
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::getCurrentSlot(int32_t* _aidl_return) {
+    *_aidl_return = impl_.GetCurrentSlot();
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::getNumberSlots(int32_t* _aidl_return) {
+    *_aidl_return = impl_.GetNumberSlots();
+    return ScopedAStatus::ok();
+}
+
+namespace {
+
+static constexpr MergeStatus ToAIDLMergeStatus(HIDLMergeStatus status) {
+    switch (status) {
+        case HIDLMergeStatus::NONE:
+            return MergeStatus::NONE;
+        case HIDLMergeStatus::UNKNOWN:
+            return MergeStatus::UNKNOWN;
+        case HIDLMergeStatus::SNAPSHOTTED:
+            return MergeStatus::SNAPSHOTTED;
+        case HIDLMergeStatus::MERGING:
+            return MergeStatus::MERGING;
+        case HIDLMergeStatus::CANCELLED:
+            return MergeStatus::CANCELLED;
+    }
+}
+
+static constexpr HIDLMergeStatus ToHIDLMergeStatus(MergeStatus status) {
+    switch (status) {
+        case MergeStatus::NONE:
+            return HIDLMergeStatus::NONE;
+        case MergeStatus::UNKNOWN:
+            return HIDLMergeStatus::UNKNOWN;
+        case MergeStatus::SNAPSHOTTED:
+            return HIDLMergeStatus::SNAPSHOTTED;
+        case MergeStatus::MERGING:
+            return HIDLMergeStatus::MERGING;
+        case MergeStatus::CANCELLED:
+            return HIDLMergeStatus::CANCELLED;
+    }
+}
+
+}
+
+ScopedAStatus BootControl::getSnapshotMergeStatus(MergeStatus* _aidl_return) {
+    *_aidl_return = ToAIDLMergeStatus(impl_.GetSnapshotMergeStatus());
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::getSuffix(int32_t in_slot, std::string* _aidl_return) {
+    if (!impl_.IsValidSlot(in_slot)) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+    }
+    *_aidl_return = impl_.GetSuffix(in_slot);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::isSlotBootable(int32_t in_slot, bool* _aidl_return) {
+    if (!impl_.IsValidSlot(in_slot)) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+    }
+    *_aidl_return = impl_.IsSlotBootable(in_slot);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::isSlotMarkedSuccessful(int32_t in_slot, bool* _aidl_return) {
+    if (!impl_.IsValidSlot(in_slot)) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+    }
+    *_aidl_return = impl_.IsSlotMarkedSuccessful(in_slot);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::markBootSuccessful() {
+    if (!impl_.MarkBootSuccessful()) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
+                                                                  "Operation failed");
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::setActiveBootSlot(int32_t in_slot) {
+    if (!impl_.IsValidSlot(in_slot)) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+    }
+    if (!impl_.SetActiveBootSlot(in_slot)) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
+                                                                  "Operation failed");
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::setSlotAsUnbootable(int32_t in_slot) {
+    if (!impl_.IsValidSlot(in_slot)) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str());
+    }
+    if (!impl_.SetSlotAsUnbootable(in_slot)) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
+                                                                  "Operation failed");
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus BootControl::setSnapshotMergeStatus(MergeStatus in_status) {
+    if (!impl_.SetSnapshotMergeStatus(ToHIDLMergeStatus(in_status))) {
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED,
+                                                                  "Operation failed");
+    }
+    return ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::boot
diff --git a/boot/aidl/default/BootControl.h b/boot/aidl/default/BootControl.h
new file mode 100644
index 0000000..54cd32d
--- /dev/null
+++ b/boot/aidl/default/BootControl.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/boot/BnBootControl.h>
+#include <libboot_control/libboot_control.h>
+
+namespace aidl::android::hardware::boot {
+
+class BootControl final : public BnBootControl {
+  public:
+    BootControl();
+    ::ndk::ScopedAStatus getActiveBootSlot(int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus getCurrentSlot(int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus getNumberSlots(int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus getSnapshotMergeStatus(
+            ::aidl::android::hardware::boot::MergeStatus* _aidl_return) override;
+    ::ndk::ScopedAStatus getSuffix(int32_t in_slot, std::string* _aidl_return) override;
+    ::ndk::ScopedAStatus isSlotBootable(int32_t in_slot, bool* _aidl_return) override;
+    ::ndk::ScopedAStatus isSlotMarkedSuccessful(int32_t in_slot, bool* _aidl_return) override;
+    ::ndk::ScopedAStatus markBootSuccessful() override;
+    ::ndk::ScopedAStatus setActiveBootSlot(int32_t in_slot) override;
+    ::ndk::ScopedAStatus setSlotAsUnbootable(int32_t in_slot) override;
+    ::ndk::ScopedAStatus setSnapshotMergeStatus(
+            ::aidl::android::hardware::boot::MergeStatus in_status) override;
+
+  private:
+    ::android::bootable::BootControl impl_;
+};
+
+}  // namespace aidl::android::hardware::boot
diff --git a/boot/aidl/default/boot-default.rc b/boot/aidl/default/boot-default.rc
new file mode 100644
index 0000000..589f803
--- /dev/null
+++ b/boot/aidl/default/boot-default.rc
@@ -0,0 +1,5 @@
+service vendor.boot-default /vendor/bin/hw/android.hardware.boot-service.default
+    class early_hal
+    user root
+    group root
+
diff --git a/boot/aidl/default/boot-default.xml b/boot/aidl/default/boot-default.xml
new file mode 100644
index 0000000..23ccc4e
--- /dev/null
+++ b/boot/aidl/default/boot-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.boot</name>
+        <fqname>IBootControl/default</fqname>
+    </hal>
+</manifest>
diff --git a/boot/aidl/default/main.cpp b/boot/aidl/default/main.cpp
new file mode 100644
index 0000000..70b284e
--- /dev/null
+++ b/boot/aidl/default/main.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BootControl.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::boot::BootControl;
+using aidl::android::hardware::boot::IBootControl;
+
+int main(int, char* argv[]) {
+    android::base::InitLogging(argv, android::base::KernelLogger);
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    std::shared_ptr<IBootControl> service = ndk::SharedRefBase::make<BootControl>();
+
+    const std::string instance = std::string(BootControl::descriptor) + "/default";
+    auto status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
+    CHECK_EQ(status, STATUS_OK) << "Failed to add service " << instance << " " << status;
+    LOG(INFO) << "IBootControl AIDL service running...";
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}
diff --git a/broadcastradio/1.0/default/OWNERS b/broadcastradio/1.0/default/OWNERS
index 57e6592..302fdd7 100644
--- a/broadcastradio/1.0/default/OWNERS
+++ b/broadcastradio/1.0/default/OWNERS
@@ -1,3 +1,4 @@
-elaurent@google.com
-mnaganov@google.com
-twasilczyk@google.com
+xuweilin@google.com
+oscarazu@google.com
+ericjeong@google.com
+keunyoung@google.com
diff --git a/broadcastradio/1.0/vts/functional/OWNERS b/broadcastradio/1.0/vts/functional/OWNERS
index 778c4a2..aa19d6a 100644
--- a/broadcastradio/1.0/vts/functional/OWNERS
+++ b/broadcastradio/1.0/vts/functional/OWNERS
@@ -1,2 +1,5 @@
 # Bug component: 533946
+xuweilin@google.com
 oscarazu@google.com
+ericjeong@google.com
+keunyoung@google.com
diff --git a/broadcastradio/1.1/default/OWNERS b/broadcastradio/1.1/default/OWNERS
index 136b607..259b91e 100644
--- a/broadcastradio/1.1/default/OWNERS
+++ b/broadcastradio/1.1/default/OWNERS
@@ -1,3 +1,5 @@
 # Automotive team
-egranata@google.com
-twasilczyk@google.com
+xuweilin@google.com
+oscarazu@google.com
+ericjeong@google.com
+keunyoung@google.com
diff --git a/broadcastradio/1.1/vts/OWNERS b/broadcastradio/1.1/vts/OWNERS
index 2c21c25..aa19d6a 100644
--- a/broadcastradio/1.1/vts/OWNERS
+++ b/broadcastradio/1.1/vts/OWNERS
@@ -1,3 +1,5 @@
 # Bug component: 533946
+xuweilin@google.com
 oscarazu@google.com
+ericjeong@google.com
 keunyoung@google.com
diff --git a/broadcastradio/2.0/default/OWNERS b/broadcastradio/2.0/default/OWNERS
index 136b607..259b91e 100644
--- a/broadcastradio/2.0/default/OWNERS
+++ b/broadcastradio/2.0/default/OWNERS
@@ -1,3 +1,5 @@
 # Automotive team
-egranata@google.com
-twasilczyk@google.com
+xuweilin@google.com
+oscarazu@google.com
+ericjeong@google.com
+keunyoung@google.com
diff --git a/broadcastradio/2.0/vts/OWNERS b/broadcastradio/2.0/vts/OWNERS
index 1ff7407..09690ef 100644
--- a/broadcastradio/2.0/vts/OWNERS
+++ b/broadcastradio/2.0/vts/OWNERS
@@ -1,6 +1,8 @@
 # Automotive team
-egranata@google.com
-twasilczyk@google.com
+xuweilin@google.com
+oscarazu@google.com
+ericjeong@google.com
+keunyoung@google.com
 
 # VTS team
 dshi@google.com
diff --git a/broadcastradio/2.0/vts/functional/OWNERS b/broadcastradio/2.0/vts/functional/OWNERS
index 2c21c25..aa19d6a 100644
--- a/broadcastradio/2.0/vts/functional/OWNERS
+++ b/broadcastradio/2.0/vts/functional/OWNERS
@@ -1,3 +1,5 @@
 # Bug component: 533946
+xuweilin@google.com
 oscarazu@google.com
+ericjeong@google.com
 keunyoung@google.com
diff --git a/broadcastradio/common/OWNERS b/broadcastradio/common/OWNERS
index 136b607..259b91e 100644
--- a/broadcastradio/common/OWNERS
+++ b/broadcastradio/common/OWNERS
@@ -1,3 +1,5 @@
 # Automotive team
-egranata@google.com
-twasilczyk@google.com
+xuweilin@google.com
+oscarazu@google.com
+ericjeong@google.com
+keunyoung@google.com
diff --git a/broadcastradio/common/utils/WorkerThread.cpp b/broadcastradio/common/utils/WorkerThread.cpp
index 31f4d3f..dd87f53 100644
--- a/broadcastradio/common/utils/WorkerThread.cpp
+++ b/broadcastradio/common/utils/WorkerThread.cpp
@@ -31,7 +31,11 @@
     return lhs.when > rhs.when;
 }
 
-WorkerThread::WorkerThread() : mIsTerminating(false), mThread(&WorkerThread::threadLoop, this) {}
+WorkerThread::WorkerThread() : mIsTerminating(false) {
+    // putting mThread in constructor instead of initializer list
+    // to ensure all class members are init before mThread starts
+    mThread = std::thread(&WorkerThread::threadLoop, this);
+}
 
 WorkerThread::~WorkerThread() {
     {
diff --git a/camera/common/aidl/Android.bp b/camera/common/aidl/Android.bp
index 19de22d..d21ae58 100644
--- a/camera/common/aidl/Android.bp
+++ b/camera/common/aidl/Android.bp
@@ -19,11 +19,6 @@
         java: {
             enabled: false,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
diff --git a/camera/device/3.8/Android.bp b/camera/device/3.8/Android.bp
deleted file mode 100644
index c3c2941..0000000
--- a/camera/device/3.8/Android.bp
+++ /dev/null
@@ -1,39 +0,0 @@
-// This file is autogenerated by hidl-gen -Landroidbp.
-
-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"],
-}
-
-hidl_interface {
-    name: "android.hardware.camera.device@3.8",
-    root: "android.hardware",
-    srcs: [
-        "types.hal",
-        "ICameraDevice.hal",
-        "ICameraDeviceCallback.hal",
-        "ICameraDeviceSession.hal",
-    ],
-    interfaces: [
-        "android.hardware.camera.common@1.0",
-        "android.hardware.camera.device@3.2",
-        "android.hardware.camera.device@3.3",
-        "android.hardware.camera.device@3.4",
-        "android.hardware.camera.device@3.5",
-        "android.hardware.camera.device@3.6",
-        "android.hardware.camera.device@3.7",
-        "android.hardware.camera.metadata@3.2",
-        "android.hardware.camera.metadata@3.3",
-        "android.hardware.camera.metadata@3.4",
-        "android.hardware.camera.metadata@3.5",
-        "android.hardware.camera.metadata@3.6",
-        "android.hardware.camera.metadata@3.8",
-        "android.hardware.graphics.common@1.0",
-        "android.hidl.base@1.0",
-    ],
-    gen_java: false,
-}
diff --git a/camera/device/3.8/ICameraDevice.hal b/camera/device/3.8/ICameraDevice.hal
deleted file mode 100644
index 09edb8b..0000000
--- a/camera/device/3.8/ICameraDevice.hal
+++ /dev/null
@@ -1,122 +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.
- */
-
-package android.hardware.camera.device@3.8;
-
-import android.hardware.camera.common@1.0::Status;
-import @3.7::ICameraDevice;
-
-/**
- * Camera device interface
- *
- * Supports the android.hardware.Camera API, and the android.hardware.camera2
- * API at LIMITED or better hardware level.
- *
- * ICameraDevice.open() must return @3.2::ICameraDeviceSession,
- * @3.5::ICameraDeviceSession, @3.6::ICameraDeviceSession,
- * @3.7::ICameraDeviceSession, or @3.8::ICameraDeviceSession.
- */
-interface ICameraDevice extends @3.7::ICameraDevice {
-    /**
-     * turnOnTorchWithStrengthLevel:
-     *
-     * Change the brightness level of the flash unit associated with this camera device
-     * and set it to value in torchStrength. This function also turns ON the torch
-     * with specified torchStrength if the torch is OFF.
-     *
-     * The torchStrength value must be within the valid range i.e. >=1 and
-     * <= FLASH_INFO_STRENGTH_MAXIMUM_LEVEL. Whenever the torch is turned OFF,
-     * the brightness level will reset to FLASH_INFO_STRENGTH_DEFAULT_LEVEL.
-     * When the client calls setTorchMode(ON) after turnOnTorchWithStrengthLevel(N),
-     * the flash unit will have brightness level equal to N. This level does not
-     * represent the real brightness units. It is linear in nature i.e. flashlight
-     * at level 10 is twice as bright as at level 5.
-     *
-     * @param torchStrength Brightness level to be set for the flashlight.
-     *
-     * @return status Status code for the operation, one of:
-     *     OK:
-     *         On a successful change to the torch strength level.
-     *     INTERNAL_ERROR:
-     *         The flash unit cannot be operated due to an unexpected internal
-     *         error.
-     *     CAMERA_IN_USE:
-     *         This status code is returned when:
-     *           - This camera device has been opened, so the torch cannot be
-     *             controlled until it is closed.
-     *           - Due to other camera devices being open, or due to other
-     *             resource constraints, the torch cannot be controlled currently.
-     *     ILLEGAL_ARGUMENT:
-     *         If the torchStrength value is not within the range i.e. < 1 or
-     *         > FLASH_INFO_STRENGTH_MAXIMUM_LEVEL.
-     *     METHOD_NOT_SUPPORTED:
-     *         This status code is returned when:
-     *           - This camera device does not support direct operation of flashlight
-     *             torch mode. The framework must open the camera device and turn
-     *             the torch on through the device interface.
-     *           - This camera device does not have a flash unit.
-     *           - This camera device has flash unit but does not support torch
-     *             strength control.
-     *     CAMERA_DISCONNECTED:
-     *         An external camera device has been disconnected, and is no longer
-     *         available. This camera device interface is now stale, and a new
-     *         instance must be acquired if the device is reconnected. All
-     *         subsequent calls on this interface must return
-     *         CAMERA_DISCONNECTED.
-     *
-     */
-    turnOnTorchWithStrengthLevel(int32_t torchStrength) generates (Status status);
-
-    /**
-     * getTorchStrengthLevel:
-     *
-     * Get current torch strength level.
-     * If the device supports torch strength control, when the torch is OFF the
-     * strength level will reset to default level, so the return
-     * value in this case will be equal to FLASH_INFO_STRENGTH_DEFAULT_LEVEL.
-     *
-     * @return status Status code for the operation, one of:
-     *      OK:
-     *           On success.
-     *      INTERNAL_ERROR:
-     *           An unexpected error occurred and the information is not
-     *           available.
-     *      METHOD_NOT_SUPPORTED:
-     *          This status code is returned when:
-     *            - This camera device does not support direct operation of flashlight
-     *              torch mode. The framework must open the camera device and turn
-     *              the torch on through the device interface.
-     *            - This camera device does not have a flash unit.
-     *            - This camera device has flash unit but does not support torch
-     *              strength control.
-     *
-     * @return torchStrength Current torch strength level.
-     *
-     */
-    getTorchStrengthLevel() generates (Status status, int32_t torchStrength);
-
-     /**
-     * isStreamCombinationSupported_3_8:
-     *
-     * Identical to @3.7::ICameraDevice.isStreamCombinationSupported, except
-     * that it takes a @3.8::StreamConfiguration parameter, which could contain
-     * additional information about a specific 10-bit dynamic range profile or
-     * stream use case.
-     *
-     */
-    isStreamCombinationSupported_3_8(StreamConfiguration streams)
-            generates (Status status, bool queryStatus);
-};
diff --git a/camera/device/3.8/ICameraDeviceCallback.hal b/camera/device/3.8/ICameraDeviceCallback.hal
deleted file mode 100644
index de0775d..0000000
--- a/camera/device/3.8/ICameraDeviceCallback.hal
+++ /dev/null
@@ -1,34 +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.
- */
-
-package android.hardware.camera.device@3.8;
-
-import @3.5::ICameraDeviceCallback;
-
-/**
- * Callback methods for the HAL to call into the framework.
- */
-interface ICameraDeviceCallback extends @3.5::ICameraDeviceCallback {
-    /**
-     * Identical to @3.5::ICameraDeviceCallback.notify, except that it takes a
-     * list of @3.8::NotifyMsg which contain readout timestamp in addition
-     * to exposure start timestamp for shutter.
-     *
-     * The readout timestamp is used for the framework to re-time the viewfinder
-     * frames targeted for SurfaceView so that preview jitter can be reduced.
-     */
-    notify_3_8(vec<NotifyMsg> msgs);
-};
diff --git a/camera/device/3.8/ICameraDeviceSession.hal b/camera/device/3.8/ICameraDeviceSession.hal
deleted file mode 100644
index c3aa836..0000000
--- a/camera/device/3.8/ICameraDeviceSession.hal
+++ /dev/null
@@ -1,98 +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.
- */
-
-package android.hardware.camera.device@3.8;
-
-import android.hardware.camera.common@1.0::Status;
-import @3.5::StreamConfiguration;
-import @3.7::ICameraDeviceSession;
-import @3.6::HalStreamConfiguration;
-
-/**
- * Camera device active session interface.
- *
- * Obtained via ICameraDevice::open(), this interface contains the methods to
- * configure and request captures from an active camera device.
- */
-interface ICameraDeviceSession extends @3.7::ICameraDeviceSession {
-    /**
-     * configureStreams_3_8:
-     *
-     * Identical to @3.7::ICameraDeviceSession.configureStreams_3_7, except that:
-     *
-     * - The requestedConfiguration allows the camera framework to configure
-     *   10-bit dynamic range profile.
-     * - The requestedConfiguration allows the camera framework to configure
-     *   stream use cases.
-     *
-     * @return status Status code for the operation, one of:
-     *     OK:
-     *         On successful stream configuration.
-     *     INTERNAL_ERROR:
-     *         If there has been a fatal error and the device is no longer
-     *         operational. Only close() can be called successfully by the
-     *         framework after this error is returned.
-     *     ILLEGAL_ARGUMENT:
-     *         If the requested stream configuration is invalid. Some examples
-     *         of invalid stream configurations include:
-     *           - Including more than 1 INPUT stream
-     *           - Not including any OUTPUT streams
-     *           - Including streams with unsupported formats, or an unsupported
-     *             size for that format.
-     *           - Including too many output streams of a certain format.
-     *           - Unsupported rotation configuration
-     *           - Stream sizes/formats don't satisfy the
-     *             StreamConfigurationMode requirements
-     *             for non-NORMAL mode, or the requested operation_mode is not
-     *             supported by the HAL.
-     *           - Unsupported usage flag
-     *           - Unsupported stream groupIds, or unsupported multi-resolution
-     *             input stream.
-     *           - Invalid combination between a 10-bit dynamic range profile
-     *             and none impl. defined 8-bit format for a particular stream.
-     *           - Unsupported stream use case
-     *         The camera service cannot filter out all possible illegal stream
-     *         configurations, since some devices may support more simultaneous
-     *         streams or larger stream resolutions than the minimum required
-     *         for a given camera device hardware level. The HAL must return an
-     *         ILLEGAL_ARGUMENT for any unsupported stream set, and then be
-     *         ready to accept a future valid stream configuration in a later
-     *         configureStreams call.
-     * @return halConfiguration The stream parameters desired by the HAL for
-     *     each stream, including maximum buffers, the usage flags, and the
-     *     override format and dataspace.
-     */
-    configureStreams_3_8(StreamConfiguration requestedConfiguration)
-        generates (Status status, @3.6::HalStreamConfiguration halConfiguration);
-
-    /**
-     * repeatingRequestEnd:
-     *
-     * Notification about the last frame number in a repeating request along with the
-     * ids of all streams included in the repeating request.
-     *
-     * This can be called at any point after 'processCaptureRequest' in response
-     * to camera clients disabling an active repeating request.
-     *
-     * 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.
-     *
-     * This method must always succeed, even if the device has encountered a
-     * serious error.
-     */
-    repeatingRequestEnd(uint32_t frameNumber, vec<int32_t> streamIds);
-};
diff --git a/camera/device/3.8/types.hal b/camera/device/3.8/types.hal
deleted file mode 100644
index 04a2450..0000000
--- a/camera/device/3.8/types.hal
+++ /dev/null
@@ -1,157 +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.
- */
-
-package android.hardware.camera.device@3.8;
-
-import @3.2::ErrorMsg;
-import @3.2::CameraMetadata;
-import @3.2::MsgType;
-import @3.2::ShutterMsg;
-import @3.2::CameraMetadata;
-import @3.2::StreamConfigurationMode;
-import @3.7::Stream;
-
-import android.hardware.camera.metadata@3.8::CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap;
-import android.hardware.camera.metadata@3.8::CameraMetadataEnumAndroidScalerAvailableStreamUseCases;
-
-/**
- * ShutterMsg:
- *
- * Message contents for MsgType::SHUTTER
- *
- * This version extends the @3.2 ShutterMsg with the readout timestamp.
- */
-struct ShutterMsg {
-    /**
-     * The definition of ShutterMsg from prior version.
-     */
-    @3.2::ShutterMsg v3_2;
-
-    /**
-     * Timestamp for the capture readout. This must be in the same time domain
-     * as v3_2.timestamp, and for a rolling shutter sensor, the value must be
-     * v3_2.timestamp + exposureTime + t_crop_top where t_crop_top is the exposure time
-     * skew of the cropped lines on the top.
-     */
-    uint64_t readoutTimestamp;
-};
-
-/**
- * NotifyMsg:
- *
- * The message structure sent to ICameraDevice3Callback::notify()
- *
- * This version extends the @3.2 NotifyMsg with the @3.8 version of ShutterMsg.
- */
-struct NotifyMsg {
-    /**
-     * The message type.
-     */
-    @3.2::MsgType type;
-
-    union Message {
-        /**
-         * Error message contents. Valid if type is MsgType::ERROR
-         */
-        @3.2::ErrorMsg error;
-
-        /**
-         * Shutter message contents. Valid if type is MsgType::SHUTTER
-         */
-        ShutterMsg shutter;
-    } msg;
-};
-
-/**
- * Stream:
- *
- * A descriptor for a single camera input or output stream. A stream is defined
- * by the framework by its buffer resolution and format, and additionally by the
- * HAL with the gralloc usage flags and the maximum in-flight buffer count.
- *
- * This version extends the @3.7 Stream with the dynamic range profile and the
- * stream use case field.
- */
-struct Stream {
-    /**
-     * The definition of Stream from the prior version.
-     */
-    @3.7::Stream v3_7;
-
-    /**
-     * The dynamic range profile for this stream.
-     *
-     * This field is valid and must only be considered for streams with format
-     * android.hardware.graphics.common.PixelFormat.YCBCR_P010 or
-     * android.hardware.graphics.common.PixelFormat.IMPLEMENTATION_DEFINED on devices supporting the
-     * ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_10_BIT capability.
-     *
-     */
-    CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap dynamicRangeProfile;
-
-    /**
-     * The stream use case describing the stream's purpose
-     *
-     * This flag provides the camera device a hint on what user scenario this
-     * stream is intended for. With this flag, the camera device can optimize
-     * camera pipeline parameters, such as tuning, sensor mode, and ISP settings,
-     * for the intended use case.
-     *
-     * When this field is set to DEFAULT, the camera device should behave in
-     * the same way as in previous HAL versions, and optimize the camera pipeline
-     * based on stream format, data space, usage flag, and other stream properties.
-     *
-     * The HAL reports supported stream use cases in
-     * ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES. If the HAL doesn't support
-     * setting stream use cases, the camera framework leaves this field as
-     * DEFAULT.
-     */
-    CameraMetadataEnumAndroidScalerAvailableStreamUseCases useCase;
-};
-
-/**
- * StreamConfiguration:
- *
- * Identical to @3.7::StreamConfiguration, except that the streams
- * vector contains @3.8::Stream.
- */
-struct StreamConfiguration {
-    /**
-     * An array of camera stream pointers, defining the input/output
-     * configuration for the camera HAL device.
-     */
-    vec<Stream> streams;
-
-    /**
-     * The definition of operation mode from prior version.
-     */
-    @3.2::StreamConfigurationMode operationMode;
-
-    /**
-     * The definition of session parameters from prior version.
-     */
-    @3.2::CameraMetadata sessionParams;
-
-    /**
-     * The definition of stream configuration counter from prior version.
-     */
-    uint32_t streamConfigCounter;
-
-    /**
-     * The definition of multi-resolution input image flag from prior version.
-     */
-    bool multiResolutionInputImage;
-};
diff --git a/camera/device/aidl/Android.bp b/camera/device/aidl/Android.bp
index afc6b8d..365a5ff 100644
--- a/camera/device/aidl/Android.bp
+++ b/camera/device/aidl/Android.bp
@@ -27,11 +27,6 @@
             sdk_version: "module_current",
             enabled: false,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
diff --git a/camera/metadata/3.8/Android.bp b/camera/metadata/3.8/Android.bp
deleted file mode 100644
index ead9543..0000000
--- a/camera/metadata/3.8/Android.bp
+++ /dev/null
@@ -1,27 +0,0 @@
-// This file is autogenerated by hidl-gen -Landroidbp.
-
-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"],
-}
-
-hidl_interface {
-    name: "android.hardware.camera.metadata@3.8",
-    root: "android.hardware",
-    srcs: [
-        "types.hal",
-    ],
-    interfaces: [
-        "android.hardware.camera.metadata@3.2",
-        "android.hardware.camera.metadata@3.3",
-        "android.hardware.camera.metadata@3.4",
-        "android.hardware.camera.metadata@3.5",
-        "android.hardware.camera.metadata@3.6",
-        "android.hardware.camera.metadata@3.7",
-    ],
-    gen_java: true,
-}
diff --git a/camera/metadata/3.8/types.hal b/camera/metadata/3.8/types.hal
deleted file mode 100644
index 8cc6646..0000000
--- a/camera/metadata/3.8/types.hal
+++ /dev/null
@@ -1,244 +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.
- */
-
-/*
- * Autogenerated from camera metadata definitions in
- * /system/media/camera/docs/metadata_definitions.xml
- * *** DO NOT EDIT BY HAND ***
- */
-
-package android.hardware.camera.metadata@3.8;
-
-import android.hardware.camera.metadata@3.2;
-import android.hardware.camera.metadata@3.3;
-import android.hardware.camera.metadata@3.4;
-import android.hardware.camera.metadata@3.5;
-import android.hardware.camera.metadata@3.6;
-import android.hardware.camera.metadata@3.7;
-
-/**
- * Top level hierarchy definitions for camera metadata. *_INFO sections are for
- * the static metadata that can be retrieved without opening the camera device.
- */
-enum CameraMetadataSection : @3.4::CameraMetadataSection {
-    ANDROID_AUTOMOTIVE =
-        android.hardware.camera.metadata@3.4::CameraMetadataSection:ANDROID_SECTION_COUNT,
-
-    ANDROID_AUTOMOTIVE_LENS,
-
-    ANDROID_SECTION_COUNT_3_8,
-
-    VENDOR_SECTION_3_8 = 0x8000,
-
-};
-
-/**
- * Hierarchy positions in enum space. All vendor extension sections must be
- * defined with tag >= VENDOR_SECTION_START
- */
-enum CameraMetadataSectionStart : android.hardware.camera.metadata@3.4::CameraMetadataSectionStart {
-    ANDROID_AUTOMOTIVE_START = CameraMetadataSection:ANDROID_AUTOMOTIVE << 16,
-
-    ANDROID_AUTOMOTIVE_LENS_START = CameraMetadataSection:ANDROID_AUTOMOTIVE_LENS << 16,
-
-    VENDOR_SECTION_START_3_8 = CameraMetadataSection:VENDOR_SECTION_3_8 << 16,
-
-};
-
-/**
- * Main enumeration for defining camera metadata tags added in this revision
- *
- * <p>Partial documentation is included for each tag; for complete documentation, reference
- * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
- */
-enum CameraMetadataTag : @3.7::CameraMetadataTag {
-    /** android.flash.info.strengthMaximumLevel [static, int32, public]
-     *
-     * <p>Maximum flashlight brightness level.</p>
-     */
-    ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_FLASH_INFO_END,
-
-    /** android.flash.info.strengthDefaultLevel [static, int32, public]
-     *
-     * <p>Default flashlight brightness level to be set via
-     * {android.hardware.camera2.CameraManager#turnOnTorchWithStrengthLevel}.</p>
-     */
-    ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL,
-
-    ANDROID_FLASH_INFO_END_3_8,
-
-    /** android.request.availableDynamicRangeProfilesMap [static, enum[], ndk_public]
-     *
-     * <p>A map of all available 10-bit dynamic range profiles along with their
-     * capture request constraints.</p>
-     */
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP = android.hardware.camera.metadata@3.4::CameraMetadataTag:ANDROID_REQUEST_END_3_4,
-
-    /** android.request.recommendedTenBitDynamicRangeProfile [static, int64, java_public]
-     *
-     * <p>Recommended 10-bit dynamic range profile.</p>
-     */
-    ANDROID_REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE,
-
-    ANDROID_REQUEST_END_3_8,
-
-    /** android.scaler.availableStreamUseCases [static, enum[], public]
-     *
-     * <p>The stream use cases supported by this camera device.</p>
-     */
-    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES = android.hardware.camera.metadata@3.6::CameraMetadataTag:ANDROID_SCALER_END_3_6,
-
-    ANDROID_SCALER_END_3_8,
-
-    /** android.automotive.location [static, enum, public]
-     *
-     * <p>Location of the cameras on the automotive devices.</p>
-     */
-    ANDROID_AUTOMOTIVE_LOCATION = CameraMetadataSectionStart:ANDROID_AUTOMOTIVE_START,
-
-    ANDROID_AUTOMOTIVE_END_3_8,
-
-    /** android.automotive.lens.facing [static, enum[], public]
-     *
-     * <p>The direction of the camera faces relative to the vehicle body frame and the
-     * passenger seats.</p>
-     */
-    ANDROID_AUTOMOTIVE_LENS_FACING = CameraMetadataSectionStart:ANDROID_AUTOMOTIVE_LENS_START,
-
-    ANDROID_AUTOMOTIVE_LENS_END_3_8,
-
-};
-
-/*
- * Enumeration definitions for the various entries that need them
- */
-
-/** android.control.videoStabilizationMode enumeration values added since v3.2
- * @see ANDROID_CONTROL_VIDEO_STABILIZATION_MODE
- */
-enum CameraMetadataEnumAndroidControlVideoStabilizationMode :
-        @3.2::CameraMetadataEnumAndroidControlVideoStabilizationMode {
-    ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION,
-};
-
-/** android.lens.poseReference enumeration values added since v3.5
- * @see ANDROID_LENS_POSE_REFERENCE
- */
-enum CameraMetadataEnumAndroidLensPoseReference :
-        @3.5::CameraMetadataEnumAndroidLensPoseReference {
-    ANDROID_LENS_POSE_REFERENCE_AUTOMOTIVE,
-};
-
-/** android.request.availableCapabilities enumeration values added since v3.6
- * @see ANDROID_REQUEST_AVAILABLE_CAPABILITIES
- */
-enum CameraMetadataEnumAndroidRequestAvailableCapabilities :
-        @3.6::CameraMetadataEnumAndroidRequestAvailableCapabilities {
-    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT,
-    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE,
-};
-
-/** android.request.availableDynamicRangeProfilesMap enumeration values
- * @see ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
- */
-enum CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap : int64_t {
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD
-                                                                 = 0x1,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10  = 0x2,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10  = 0x4,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS
-                                                                 = 0x8,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF
-                                                                 = 0x10,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO
-                                                                 = 0x20,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM
-                                                                 = 0x40,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO
-                                                                 = 0x80,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF
-                                                                 = 0x100,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO
-                                                                 = 0x200,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM
-                                                                 = 0x400,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO
-                                                                 = 0x800,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX    = 0x1000,
-};
-
-/** android.scaler.availableRecommendedStreamConfigurations enumeration values added since v3.4
- * @see ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS
- */
-enum CameraMetadataEnumAndroidScalerAvailableRecommendedStreamConfigurations :
-        @3.4::CameraMetadataEnumAndroidScalerAvailableRecommendedStreamConfigurations {
-    ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_10BIT_OUTPUT
-                                                                 = 0x8,
-    ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END_3_8
-                                                                 = 0x9,
-};
-
-/** android.scaler.availableStreamUseCases enumeration values
- * @see ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES
- */
-enum CameraMetadataEnumAndroidScalerAvailableStreamUseCases : int64_t {
-    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT           = 0x0,
-    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW           = 0x1,
-    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE     = 0x2,
-    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD      = 0x3,
-    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL
-                                                                 = 0x4,
-    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL        = 0x5,
-    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START      = 0x10000,
-};
-
-/** android.automotive.location enumeration values
- * @see ANDROID_AUTOMOTIVE_LOCATION
- */
-enum CameraMetadataEnumAndroidAutomotiveLocation : uint32_t {
-    ANDROID_AUTOMOTIVE_LOCATION_INTERIOR,
-    ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_OTHER,
-    ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_FRONT,
-    ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_REAR,
-    ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_LEFT,
-    ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_RIGHT,
-    ANDROID_AUTOMOTIVE_LOCATION_EXTRA_OTHER,
-    ANDROID_AUTOMOTIVE_LOCATION_EXTRA_FRONT,
-    ANDROID_AUTOMOTIVE_LOCATION_EXTRA_REAR,
-    ANDROID_AUTOMOTIVE_LOCATION_EXTRA_LEFT,
-    ANDROID_AUTOMOTIVE_LOCATION_EXTRA_RIGHT,
-};
-
-/** android.automotive.lens.facing enumeration values
- * @see ANDROID_AUTOMOTIVE_LENS_FACING
- */
-enum CameraMetadataEnumAndroidAutomotiveLensFacing : uint32_t {
-    ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_OTHER,
-    ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_FRONT,
-    ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_REAR,
-    ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_LEFT,
-    ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_RIGHT,
-    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_OTHER,
-    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_LEFT,
-    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_CENTER,
-    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_RIGHT,
-    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_LEFT,
-    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_CENTER,
-    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_RIGHT,
-    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_LEFT,
-    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_CENTER,
-    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_RIGHT,
-};
diff --git a/camera/metadata/aidl/Android.bp b/camera/metadata/aidl/Android.bp
index 31d4b4d..301a943 100644
--- a/camera/metadata/aidl/Android.bp
+++ b/camera/metadata/aidl/Android.bp
@@ -19,11 +19,6 @@
         java: {
             enabled: false,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index 2f24dfd..85e69eb 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -50,9 +50,7 @@
         "android.hardware.camera.device@3.5",
         "android.hardware.camera.device@3.6",
         "android.hardware.camera.device@3.7",
-        "android.hardware.camera.device@3.8",
         "android.hardware.camera.metadata@3.4",
-        "android.hardware.camera.metadata@3.8",
         "android.hardware.camera.provider@2.4",
         "android.hardware.camera.provider@2.5",
         "android.hardware.camera.provider@2.6",
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index f89c71d..6866776 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -42,14 +42,9 @@
 #include <android/hardware/camera/device/3.6/ICameraDevice.h>
 #include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
 #include <android/hardware/camera/device/3.7/ICameraDevice.h>
-#include <android/hardware/camera/device/3.8/ICameraDevice.h>
 #include <android/hardware/camera/device/3.7/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.8/ICameraDeviceSession.h>
 #include <android/hardware/camera/device/3.7/ICameraInjectionSession.h>
-#include <android/hardware/camera/device/3.8/ICameraDeviceCallback.h>
-#include <android/hardware/camera/device/3.8/ICameraDeviceSession.h>
 #include <android/hardware/camera/metadata/3.4/types.h>
-#include <android/hardware/camera/metadata/3.8/types.h>
 #include <android/hardware/camera/provider/2.4/ICameraProvider.h>
 #include <android/hardware/camera/provider/2.5/ICameraProvider.h>
 #include <android/hardware/camera/provider/2.6/ICameraProvider.h>
@@ -134,10 +129,6 @@
         CameraMetadataEnumAndroidSensorInfoColorFilterArrangement;
 using ::android::hardware::camera::metadata::V3_4::CameraMetadataTag;
 using ::android::hardware::camera::metadata::V3_6::CameraMetadataEnumAndroidSensorPixelMode;
-using ::android::hardware::camera::metadata::V3_8::
-        CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap;
-using ::android::hardware::camera::metadata::V3_8::
-        CameraMetadataEnumAndroidScalerAvailableStreamUseCases;
 using ::android::hardware::camera::provider::V2_4::ICameraProvider;
 using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
 using ::android::hardware::camera::provider::V2_6::CameraIdAndStreamCombination;
@@ -233,8 +224,7 @@
 
 namespace {
     // "device@<version>/legacy/<id>"
-    const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)";
-    const int CAMERA_DEVICE_API_VERSION_3_8 = 0x308;
+    const char* kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)";
     const int CAMERA_DEVICE_API_VERSION_3_7 = 0x307;
     const int CAMERA_DEVICE_API_VERSION_3_6 = 0x306;
     const int CAMERA_DEVICE_API_VERSION_3_5 = 0x305;
@@ -242,19 +232,16 @@
     const int CAMERA_DEVICE_API_VERSION_3_3 = 0x303;
     const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302;
     const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100;
-    const char *kHAL3_8 = "3.8";
-    const char *kHAL3_7 = "3.7";
-    const char *kHAL3_6 = "3.6";
-    const char *kHAL3_5 = "3.5";
-    const char *kHAL3_4 = "3.4";
-    const char *kHAL3_3 = "3.3";
-    const char *kHAL3_2 = "3.2";
-    const char *kHAL1_0 = "1.0";
+    const char* kHAL3_7 = "3.7";
+    const char* kHAL3_6 = "3.6";
+    const char* kHAL3_5 = "3.5";
+    const char* kHAL3_4 = "3.4";
+    const char* kHAL3_3 = "3.3";
+    const char* kHAL3_2 = "3.2";
+    const char* kHAL1_0 = "1.0";
 
-    bool matchDeviceName(const hidl_string& deviceName,
-            const hidl_string &providerType,
-            std::string* deviceVersion,
-            std::string* cameraId) {
+    bool matchDeviceName(const hidl_string& deviceName, const hidl_string& providerType,
+                         std::string* deviceVersion, std::string* cameraId) {
         ::android::String8 pattern;
         pattern.appendFormat(kDeviceNameRE, providerType.c_str());
         std::regex e(pattern.string());
@@ -280,9 +267,7 @@
             return -1;
         }
 
-        if (version.compare(kHAL3_8) == 0) {
-            return CAMERA_DEVICE_API_VERSION_3_8;
-        } else if (version.compare(kHAL3_7) == 0) {
+        if (version.compare(kHAL3_7) == 0) {
             return CAMERA_DEVICE_API_VERSION_3_7;
         } else if (version.compare(kHAL3_6) == 0) {
             return CAMERA_DEVICE_API_VERSION_3_6;
@@ -652,7 +637,8 @@
      }
 
      virtual Return<void> processCaptureResult_3_4(
-         const hidl_vec<V3_4::CaptureResult>& /*results*/) override {
+
+             const hidl_vec<V3_4::CaptureResult>& /*results*/) override {
          ALOGI("processCaptureResult_3_4 callback");
          ADD_FAILURE();  // Empty callback should not reach here
          return Void();
@@ -682,44 +668,41 @@
      }
  };
 
-    struct DeviceCb : public V3_8::ICameraDeviceCallback {
-        DeviceCb(CameraHidlTest *parent, int deviceVersion, const camera_metadata_t *staticMeta) :
-                mParent(parent), mDeviceVersion(deviceVersion) {
+    struct DeviceCb : public V3_5::ICameraDeviceCallback {
+        DeviceCb(CameraHidlTest* parent, int deviceVersion, const camera_metadata_t* staticMeta)
+            : mParent(parent), mDeviceVersion(deviceVersion) {
             mStaticMetadata = staticMeta;
         }
 
-        Return<void> processCaptureResult_3_4(
-                const hidl_vec<V3_4::CaptureResult>& results) override;
+        Return<void> processCaptureResult_3_4(const hidl_vec<V3_4::CaptureResult>& results) override;
         Return<void> processCaptureResult(const hidl_vec<CaptureResult>& results) override;
         Return<void> notify(const hidl_vec<NotifyMsg>& msgs) override;
-        Return<void> notify_3_8(const hidl_vec<V3_8::NotifyMsg>& msgs) override;
 
-        Return<void> requestStreamBuffers(
-                const hidl_vec<V3_5::BufferRequest>& bufReqs,
-                requestStreamBuffers_cb _hidl_cb) override;
+        Return<void> requestStreamBuffers(const hidl_vec<V3_5::BufferRequest>& bufReqs,
+                                          requestStreamBuffers_cb _hidl_cb) override;
 
         Return<void> returnStreamBuffers(const hidl_vec<StreamBuffer>& buffers) override;
 
         void setCurrentStreamConfig(const hidl_vec<V3_4::Stream>& streams,
-                const hidl_vec<V3_2::HalStream>& halStreams);
+                                     const hidl_vec<V3_2::HalStream>& halStreams);
 
         void waitForBuffersReturned();
 
       private:
         bool processCaptureResultLocked(const CaptureResult& results,
-                hidl_vec<PhysicalCameraMetadata> physicalCameraMetadata);
+                                        hidl_vec<PhysicalCameraMetadata> physicalCameraMetadata);
         Return<void> notifyHelper(const hidl_vec<NotifyMsg>& msgs,
-                const std::vector<std::pair<bool, nsecs_t>>& readoutTimestamps);
+                                  const std::vector<std::pair<bool, nsecs_t>>& readoutTimestamps);
 
-        CameraHidlTest *mParent; // Parent object
+        CameraHidlTest* mParent;  // Parent object
         int mDeviceVersion;
         android::hardware::camera::common::V1_0::helper::CameraMetadata mStaticMetadata;
         bool hasOutstandingBuffersLocked();
 
         /* members for requestStreamBuffers() and returnStreamBuffers()*/
-        std::mutex mLock; // protecting members below
-        bool                      mUseHalBufManager = false;
-        hidl_vec<V3_4::Stream>    mStreams;
+        std::mutex mLock;  // protecting members below
+        bool mUseHalBufManager = false;
+        hidl_vec<V3_4::Stream> mStreams;
         hidl_vec<V3_2::HalStream> mHalStreams;
         uint64_t mNextBufferId = 1;
         using OutstandingBuffers = std::unordered_map<uint64_t, hidl_handle>;
@@ -814,20 +797,18 @@
                       sp<provider::V2_5::ICameraProvider>* provider2_5 /*out*/,
                       sp<provider::V2_6::ICameraProvider>* provider2_6 /*out*/,
                       sp<provider::V2_7::ICameraProvider>* provider2_7 /*out*/);
-    void castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
-            sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
-            sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
-            sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/,
-            sp<device::V3_6::ICameraDeviceSession> *session3_6 /*out*/,
-            sp<device::V3_7::ICameraDeviceSession> *session3_7 /*out*/,
-            sp<device::V3_8::ICameraDeviceSession> *session3_8 /*out*/);
+    void castSession(const sp<ICameraDeviceSession>& session, int32_t deviceVersion,
+                     sp<device::V3_3::ICameraDeviceSession>* session3_3 /*out*/,
+                     sp<device::V3_4::ICameraDeviceSession>* session3_4 /*out*/,
+                     sp<device::V3_5::ICameraDeviceSession>* session3_5 /*out*/,
+                     sp<device::V3_6::ICameraDeviceSession>* session3_6 /*out*/,
+                     sp<device::V3_7::ICameraDeviceSession>* session3_7 /*out*/);
     void castInjectionSession(
             const sp<ICameraDeviceSession>& session,
             sp<device::V3_7::ICameraInjectionSession>* injectionSession3_7 /*out*/);
     void castDevice(const sp<device::V3_2::ICameraDevice>& device, int32_t deviceVersion,
                     sp<device::V3_5::ICameraDevice>* device3_5 /*out*/,
-                    sp<device::V3_7::ICameraDevice>* device3_7 /*out*/,
-                    sp<device::V3_8::ICameraDevice>* device3_8 /*out*/);
+                    sp<device::V3_7::ICameraDevice>* device3_7 /*out*/);
     void createStreamConfiguration(
             const ::android::hardware::hidl_vec<V3_2::Stream>& streams3_2,
             StreamConfigurationMode configMode,
@@ -857,16 +838,6 @@
                              uint32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
                              sp<DeviceCb>* outCb /*out*/, uint32_t streamConfigCounter,
                              bool maxResolution);
-    void configureStreams3_8(const std::string& name, int32_t deviceVersion,
-                             sp<ICameraProvider> provider, PixelFormat format,
-                             sp<device::V3_8::ICameraDeviceSession>* session3_8 /*out*/,
-                             V3_2::Stream* previewStream /*out*/,
-                             device::V3_6::HalStreamConfiguration* halStreamConfig /*out*/,
-                             bool* supportsPartialResults /*out*/,
-                             uint32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
-                             sp<DeviceCb>* outCb /*out*/, uint32_t streamConfigCounter,
-                             bool maxResolution,
-                             CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap prof);
 
     void configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
             sp<ICameraProvider> provider,
@@ -947,9 +918,6 @@
     static bool isDepthOnly(const camera_metadata_t* staticMeta);
 
     static bool isUltraHighResolution(const camera_metadata_t* staticMeta);
-    static void get10BitDynamicRangeProfiles(const camera_metadata_t* staticMeta,
-        std::vector<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap> *profiles);
-    static bool is10BitDynamicRangeCapable(const camera_metadata_t* staticMeta);
 
     static Status getAvailableOutputStreams(const camera_metadata_t* staticMeta,
                                             std::vector<AvailableStream>& outputStreams,
@@ -1130,10 +1098,6 @@
                 expectedPhysicalResults(extraPhysicalResult) {}
     };
 
-    static void verify10BitMetadata(HandleImporter& importer,
-            const InFlightRequest& request,
-            CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap profile);
-
     // Map from frame number to the in-flight request state
     typedef ::android::KeyedVector<uint32_t, InFlightRequest*> InFlightMap;
 
@@ -1564,32 +1528,6 @@
     }
 }
 
-Return<void> CameraHidlTest::DeviceCb::notify_3_8(
-        const hidl_vec<V3_8::NotifyMsg>& msgs) {
-    hidl_vec<NotifyMsg> msgs3_2;
-    std::vector<std::pair<bool, nsecs_t>> readoutTimestamps;
-
-    nsecs_t count = msgs.size();
-    msgs3_2.resize(count);
-    readoutTimestamps.resize(count);
-
-    for (size_t i = 0; i < count; i++) {
-        msgs3_2[i].type = msgs[i].type;
-        switch (msgs[i].type) {
-            case MsgType::ERROR:
-                msgs3_2[i].msg.error = msgs[i].msg.error;
-                readoutTimestamps[i] = {false, 0};
-                break;
-            case MsgType::SHUTTER:
-                msgs3_2[i].msg.shutter = msgs[i].msg.shutter.v3_2;
-                readoutTimestamps[i] = {true, msgs[i].msg.shutter.readoutTimestamp};
-                break;
-        }
-    }
-
-    return notifyHelper(msgs3_2, readoutTimestamps);
-}
-
 Return<void> CameraHidlTest::DeviceCb::notify(
         const hidl_vec<NotifyMsg>& messages) {
     std::vector<std::pair<bool, nsecs_t>> readoutTimestamps;
@@ -2082,7 +2020,6 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_8:
             case CAMERA_DEVICE_API_VERSION_3_7:
             case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
@@ -2127,7 +2064,6 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_8:
             case CAMERA_DEVICE_API_VERSION_3_7:
             case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
@@ -2869,7 +2805,6 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_8:
             case CAMERA_DEVICE_API_VERSION_3_7:
             case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
@@ -2957,7 +2892,6 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_8:
             case CAMERA_DEVICE_API_VERSION_3_7:
             case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
@@ -3018,137 +2952,6 @@
     }
 }
 
-// Verify that the torch strength level can be set and retrieved successfully.
-TEST_P(CameraHidlTest, turnOnTorchWithStrengthLevel) {
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
-    bool torchControlSupported = false;
-    bool torchStrengthControlSupported = false;
-    Return<void> ret;
-
-    ret = mProvider->isSetTorchModeSupported([&](auto status, bool support) {
-        ALOGI("isSetTorchModeSupported returns status:%d supported:%d", (int)status, support);
-        ASSERT_EQ(Status::OK, status);
-        torchControlSupported = support;
-    });
-
-    sp<TorchProviderCb> cb = new TorchProviderCb(this);
-    Return<Status> returnStatus = mProvider->setCallback(cb);
-    ASSERT_TRUE(returnStatus.isOk());
-    ASSERT_EQ(Status::OK, returnStatus);
-
-    for (const auto& name : cameraDeviceNames) {
-        int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        int32_t defaultLevel;
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_8: {
-                ::android::sp<::android::hardware::camera::device::V3_8::ICameraDevice> device3_8;
-                ALOGI("%s: Testing camera device %s", __FUNCTION__, name.c_str());
-                ret = mProvider->getCameraDeviceInterface_V3_x(
-                        name, [&](auto status, const auto& device) {
-                            ASSERT_EQ(Status::OK, status);
-                            ASSERT_NE(device, nullptr);
-                            auto castResult = device::V3_8::ICameraDevice::castFrom(device);
-                            ASSERT_TRUE(castResult.isOk());
-                            device3_8 = castResult;
-                        });
-                ASSERT_TRUE(ret.isOk());
-
-                ret = device3_8->getCameraCharacteristics([&] (auto s, const auto& chars) {
-                    ASSERT_EQ(Status::OK, s);
-                    const camera_metadata_t* staticMeta =
-                            reinterpret_cast<const camera_metadata_t*>(chars.data());
-                    ASSERT_NE(nullptr, staticMeta);
-                    torchStrengthControlSupported = isTorchStrengthControlSupported(staticMeta);
-                    camera_metadata_ro_entry entry;
-                    int rc = find_camera_metadata_ro_entry(staticMeta,
-                            ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL, &entry);
-                    if (torchStrengthControlSupported) {
-                        ASSERT_EQ(rc, 0);
-                        ASSERT_GT(entry.count, 0);
-                        defaultLevel = *entry.data.i32;
-                        ALOGI("Default level is:%d", defaultLevel);
-                    }
-                });
-                ASSERT_TRUE(ret.isOk());
-                // If torchStrengthControl is supported, torchControlSupported should be true.
-                if (torchStrengthControlSupported) {
-                    ASSERT_TRUE(torchControlSupported);
-                }
-                mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
-                returnStatus = device3_8->turnOnTorchWithStrengthLevel(2);
-                ASSERT_TRUE(returnStatus.isOk());
-                // Method_not_supported check
-                if (!torchStrengthControlSupported) {
-                    ALOGI("Torch strength control not supported.");
-                    ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, returnStatus);
-                } else {
-                    ASSERT_EQ(Status::OK, returnStatus);
-                    if (returnStatus == Status::OK) {
-                        {
-                            std::unique_lock<std::mutex> l(mTorchLock);
-                            while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
-                                auto timeout = std::chrono::system_clock::now() +
-                                        std::chrono::seconds(kTorchTimeoutSec);
-                                ASSERT_NE(std::cv_status::timeout, mTorchCond.wait_until(l,
-                                        timeout));
-                            }
-                            ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus);
-                            mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
-                        }
-                        ALOGI("getTorchStrengthLevel: Testing");
-                        ret = device3_8->getTorchStrengthLevel([&]
-                                (auto status, const auto& strengthLevel) {
-                                    ASSERT_TRUE(ret.isOk());
-                                    ASSERT_EQ(Status::OK, status);
-                                    ALOGI("Torch strength level is : %d", strengthLevel);
-                                    ASSERT_EQ(strengthLevel, 2);
-                                });
-                        // Turn OFF the torch and verify torch strength level is reset to default level.
-                        ALOGI("Testing torch strength level reset after turning the torch OFF.");
-                        returnStatus = device3_8->setTorchMode(TorchMode::OFF);
-                        ASSERT_TRUE(returnStatus.isOk());
-                        ASSERT_EQ(Status::OK, returnStatus);
-                        {
-                            std::unique_lock<std::mutex> l(mTorchLock);
-                            while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
-                                auto timeout = std::chrono::system_clock::now() +
-                                        std::chrono::seconds(kTorchTimeoutSec);
-                                ASSERT_NE(std::cv_status::timeout, mTorchCond.wait_until(l,
-                                        timeout));
-                            }
-                            ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, mTorchStatus);
-                        }
-                        ret = device3_8->getTorchStrengthLevel([&]
-                                (auto status, const auto& strengthLevel) {
-                                    ASSERT_TRUE(ret.isOk());
-                                    ASSERT_EQ(Status::OK, status);
-                                    ALOGI("Torch strength level after turning OFF torch is : %d",
-                                            strengthLevel);
-                                    ASSERT_EQ(strengthLevel, defaultLevel);
-                                });
-                    }
-                }
-            }
-            break;
-            case CAMERA_DEVICE_API_VERSION_3_7:
-            case CAMERA_DEVICE_API_VERSION_3_6:
-            case CAMERA_DEVICE_API_VERSION_3_5:
-            case CAMERA_DEVICE_API_VERSION_3_4:
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2:
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                ALOGI("Torch strength control feature not supported.");
-            }
-            break;
-            default: {
-                ALOGI("Invalid device version.");
-                ADD_FAILURE();
-            }
-            break;
-        }
-    }
-}
-
 //In case it is supported verify that torch can be enabled.
 //Check for corresponding toch callbacks as well.
 TEST_P(CameraHidlTest, setTorchMode) {
@@ -3170,7 +2973,6 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_8:
             case CAMERA_DEVICE_API_VERSION_3_7:
             case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
@@ -3299,7 +3101,6 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_8:
             case CAMERA_DEVICE_API_VERSION_3_7:
             case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
@@ -3367,7 +3168,6 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_8:
             case CAMERA_DEVICE_API_VERSION_3_7:
             case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
@@ -3401,13 +3201,10 @@
                 sp<device::V3_5::ICameraDeviceSession> sessionV3_5;
                 sp<device::V3_6::ICameraDeviceSession> sessionV3_6;
                 sp<device::V3_7::ICameraDeviceSession> sessionV3_7;
-                sp<device::V3_8::ICameraDeviceSession> sessionV3_8;
-                castSession(session, deviceVersion, &sessionV3_3,
-                        &sessionV3_4, &sessionV3_5, &sessionV3_6,
-                        &sessionV3_7, &sessionV3_8);
-                if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_8) {
-                    ASSERT_TRUE(sessionV3_8.get() != nullptr);
-                } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_7) {
+                castSession(session, deviceVersion, &sessionV3_3, &sessionV3_4, &sessionV3_5,
+                            &sessionV3_6, &sessionV3_7);
+
+                if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_7) {
                     ASSERT_TRUE(sessionV3_7.get() != nullptr);
                 } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_6) {
                     ASSERT_TRUE(sessionV3_6.get() != nullptr);
@@ -3417,7 +3214,7 @@
                     ASSERT_TRUE(sessionV3_4.get() != nullptr);
                 } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_3) {
                     ASSERT_TRUE(sessionV3_3.get() != nullptr);
-                } else { //V3_2
+                } else {  // V3_2
                     ASSERT_TRUE(sessionV3_3.get() == nullptr);
                     ASSERT_TRUE(sessionV3_4.get() == nullptr);
                     ASSERT_TRUE(sessionV3_5.get() == nullptr);
@@ -3473,7 +3270,6 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_8:
             case CAMERA_DEVICE_API_VERSION_3_7:
             case CAMERA_DEVICE_API_VERSION_3_6:
             case CAMERA_DEVICE_API_VERSION_3_5:
@@ -3575,17 +3371,14 @@
         sp<device::V3_5::ICameraDeviceSession> session3_5;
         sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_7::ICameraDeviceSession> session3_7;
-        sp<device::V3_8::ICameraDeviceSession> session3_8;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         sp<device::V3_7::ICameraDevice> cameraDevice3_7;
-        sp<device::V3_8::ICameraDevice> cameraDevice3_8;
         openEmptyDeviceSession(name, mProvider,
                 &session /*out*/, &staticMeta /*out*/, &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-                &session3_6, &session3_7, &session3_8);
-        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
-                &cameraDevice3_8);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+                    &session3_7);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
 
         outputStreams.clear();
         ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
@@ -3681,11 +3474,9 @@
         sp<device::V3_5::ICameraDeviceSession> session3_5;
         sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_7::ICameraDeviceSession> session3_7;
-        sp<device::V3_8::ICameraDeviceSession> session3_8;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         sp<device::V3_7::ICameraDevice> cameraDevice3_7;
-        sp<device::V3_8::ICameraDevice> cameraDevice3_8;
         ::android::hardware::camera::device::V3_7::StreamConfiguration config3_7;
         ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
         ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
@@ -3722,9 +3513,8 @@
             openEmptyDeviceSession(name, mProvider2_6, &cti.session /*out*/,
                                    &cti.staticMeta /*out*/, &cti.cameraDevice /*out*/);
             castSession(cti.session, deviceVersion, &cti.session3_3, &cti.session3_4,
-                        &cti.session3_5, &cti.session3_6, &cti.session3_7, &cti.session3_8);
-            castDevice(cti.cameraDevice, deviceVersion, &cti.cameraDevice3_5, &cti.cameraDevice3_7,
-                    &cti.cameraDevice3_8);
+                        &cti.session3_5, &cti.session3_6, &cti.session3_7);
+            castDevice(cti.cameraDevice, deviceVersion, &cti.cameraDevice3_5, &cti.cameraDevice3_7);
 
             outputStreams.clear();
             ASSERT_EQ(Status::OK, getMandatoryConcurrentStreams(cti.staticMeta, &outputStreams));
@@ -3853,17 +3643,14 @@
         sp<device::V3_5::ICameraDeviceSession> session3_5;
         sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_7::ICameraDeviceSession> session3_7;
-        sp<device::V3_8::ICameraDeviceSession> session3_8;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         sp<device::V3_7::ICameraDevice> cameraDevice3_7;
-        sp<device::V3_8::ICameraDevice> cameraDevice3_8;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-                &session3_6, &session3_7, &session3_8);
-        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
-                &cameraDevice3_8);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+                    &session3_7);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
 
         outputStreams.clear();
         ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
@@ -4069,17 +3856,14 @@
         sp<device::V3_5::ICameraDeviceSession> session3_5;
         sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_7::ICameraDeviceSession> session3_7;
-        sp<device::V3_8::ICameraDeviceSession> session3_8;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         sp<device::V3_7::ICameraDevice> cameraDevice3_7;
-        sp<device::V3_8::ICameraDevice> cameraDevice3_8;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-                &session3_6, &session3_7, &session3_8);
-        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
-                &cameraDevice3_8);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+                    &session3_7);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
 
         Status rc = isZSLModeAvailable(staticMeta);
         if (Status::METHOD_NOT_SUPPORTED == rc) {
@@ -4258,10 +4042,9 @@
         sp<device::V3_5::ICameraDeviceSession> session3_5;
         sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_7::ICameraDeviceSession> session3_7;
-        sp<device::V3_8::ICameraDeviceSession> session3_8;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMetaBuffer /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-                &session3_6, &session3_7, &session3_8);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+                    &session3_7);
         if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) {
             ASSERT_NE(session3_4, nullptr);
         } else {
@@ -4400,17 +4183,14 @@
         sp<device::V3_5::ICameraDeviceSession> session3_5;
         sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_7::ICameraDeviceSession> session3_7;
-        sp<device::V3_8::ICameraDeviceSession> session3_8;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         sp<device::V3_7::ICameraDevice> cameraDevice3_7;
-        sp<device::V3_8::ICameraDevice> cameraDevice3_8;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-                &session3_6, &session3_7, &session3_8);
-        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
-                &cameraDevice3_8);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+                    &session3_7);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
 
         // Check if camera support depth only
         if (isDepthOnly(staticMeta)) {
@@ -4537,17 +4317,14 @@
         sp<device::V3_5::ICameraDeviceSession> session3_5;
         sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_7::ICameraDeviceSession> session3_7;
-        sp<device::V3_8::ICameraDeviceSession> session3_8;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         sp<device::V3_7::ICameraDevice> cameraDevice3_7;
-        sp<device::V3_8::ICameraDevice> cameraDevice3_8;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-                &session3_6, &session3_7, &session3_8);
-        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
-                &cameraDevice3_8);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+                    &session3_7);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
 
         Status rc = isConstrainedModeAvailable(staticMeta);
         if (Status::METHOD_NOT_SUPPORTED == rc) {
@@ -4820,17 +4597,14 @@
         sp<device::V3_5::ICameraDeviceSession> session3_5;
         sp<device::V3_6::ICameraDeviceSession> session3_6;
         sp<device::V3_7::ICameraDeviceSession> session3_7;
-        sp<device::V3_8::ICameraDeviceSession> session3_8;
         sp<device::V3_2::ICameraDevice> cameraDevice;
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         sp<device::V3_7::ICameraDevice> cameraDevice3_7;
-        sp<device::V3_8::ICameraDevice> cameraDevice3_8;
         openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
                 &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-                &session3_6, &session3_7, &session3_8);
-        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
-                &cameraDevice3_8);
+        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+                    &session3_7);
+        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
 
         // Check if camera support depth only
         if (isDepthOnly(staticMeta)) {
@@ -5069,28 +4843,6 @@
             ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
             ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].buffer.streamId);
 
-            // For camera device 3.8 or newer, shutterReadoutTimestamp must be
-            // available, and it must be >= shutterTimestamp + exposureTime, and
-            // < shutterTimestamp + exposureTime + rollingShutterSkew / 2.
-            if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_8) {
-                ASSERT_TRUE(inflightReq.shutterReadoutTimestampValid);
-                ASSERT_FALSE(inflightReq.collectedResult.isEmpty());
-                if (inflightReq.collectedResult.exists(ANDROID_SENSOR_EXPOSURE_TIME)) {
-                    camera_metadata_entry_t exposureTimeResult = inflightReq.collectedResult.find(
-                            ANDROID_SENSOR_EXPOSURE_TIME);
-                    nsecs_t exposureToReadout =
-                            inflightReq.shutterReadoutTimestamp - inflightReq.shutterTimestamp;
-                    ASSERT_GE(exposureToReadout, exposureTimeResult.data.i64[0]);
-                    if (inflightReq.collectedResult.exists(ANDROID_SENSOR_ROLLING_SHUTTER_SKEW)) {
-                        camera_metadata_entry_t rollingShutterSkew =
-                                inflightReq.collectedResult.find(
-                                        ANDROID_SENSOR_ROLLING_SHUTTER_SKEW);
-                        ASSERT_LT(exposureToReadout, exposureTimeResult.data.i64[0] +
-                                                             rollingShutterSkew.data.i64[0] / 2);
-                    }
-                }
-            }
-
             request.frameNumber++;
             // Empty settings should be supported after the first call
             // for repeating requests.
@@ -5114,20 +4866,6 @@
         ASSERT_EQ(Status::OK, status);
         ASSERT_EQ(numRequestProcessed, 1u);
 
-        if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_8) {
-            sp<device::V3_3::ICameraDeviceSession> session3_3;
-            sp<device::V3_4::ICameraDeviceSession> session3_4;
-            sp<device::V3_5::ICameraDeviceSession> session3_5;
-            sp<device::V3_6::ICameraDeviceSession> session3_6;
-            sp<device::V3_7::ICameraDeviceSession> session3_7;
-            sp<device::V3_8::ICameraDeviceSession> session3_8;
-            castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-                    &session3_6, &session3_7, &session3_8);
-            ASSERT_TRUE(session3_8.get() != nullptr);
-            hidl_vec<int32_t> streamIds = { halStreamConfig.streams[0].id };
-            session3_8->repeatingRequestEnd(request.frameNumber, streamIds);
-        }
-
         {
             std::unique_lock<std::mutex> l(mLock);
             while (!inflightReq.errorCodeValid &&
@@ -5153,196 +4891,6 @@
     }
 }
 
-TEST_P(CameraHidlTest, processCaptureRequestPreviewStabilization) {
-    std::unordered_map<std::string, nsecs_t> cameraDeviceToTimeLag;
-    processPreviewStabilizationCaptureRequestInternal(/*previewStabilizationOn*/ false,
-                                                      cameraDeviceToTimeLag);
-    processPreviewStabilizationCaptureRequestInternal(/*previewStabilizationOn*/ true,
-                                                      cameraDeviceToTimeLag);
-}
-
-void CameraHidlTest::processPreviewStabilizationCaptureRequestInternal(
-        bool previewStabilizationOn,
-        // Used as output when preview stabilization is off, as output when its
-        // on.
-        std::unordered_map<std::string, nsecs_t>& cameraDeviceToTimeLag) {
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
-    AvailableStream streamThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
-                                       static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
-    uint64_t bufferId = 1;
-    uint32_t frameNumber = 1;
-    ::android::hardware::hidl_vec<uint8_t> settings;
-
-    for (const auto& name : cameraDeviceNames) {
-        int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
-            continue;
-        } else if (deviceVersion <= 0) {
-            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-            ADD_FAILURE();
-            return;
-        }
-
-        if (!supportsPreviewStabilization(name, mProvider)) {
-            ALOGI(" %s Camera device %s doesn't support preview stabilization, skipping", __func__,
-                  name.c_str());
-            continue;
-        }
-
-        if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_8) {
-            ALOGE("%s: device version < 3.8 must not advertise preview stabilization,"
-                  " camera metadata validation will fail",
-                  __func__);
-            ADD_FAILURE();
-        }
-
-        V3_2::Stream testStream;
-        HalStreamConfiguration halStreamConfig;
-        sp<ICameraDeviceSession> session;
-        sp<DeviceCb> cb;
-        bool supportsPartialResults = false;
-        bool useHalBufManager = false;
-        uint32_t partialResultCount = 0;
-        configureSingleStream(name, deviceVersion, mProvider, &streamThreshold,
-                              GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, RequestTemplate::PREVIEW,
-                              &session /*out*/, &testStream /*out*/, &halStreamConfig /*out*/,
-                              &supportsPartialResults /*out*/, &partialResultCount /*out*/,
-                              &useHalBufManager /*out*/, &cb /*out*/);
-
-        std::shared_ptr<ResultMetadataQueue> resultQueue;
-        auto resultQueueRet =
-                session->getCaptureResultMetadataQueue([&resultQueue](const auto& descriptor) {
-                    resultQueue = std::make_shared<ResultMetadataQueue>(descriptor);
-                    if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
-                        ALOGE("%s: HAL returns empty result metadata fmq,"
-                              " not use it",
-                              __func__);
-                        resultQueue = nullptr;
-                        // Don't use the queue onwards.
-                    }
-                });
-        ASSERT_TRUE(resultQueueRet.isOk());
-
-        InFlightRequest inflightReq = {1, false, supportsPartialResults, partialResultCount,
-                                       resultQueue};
-
-        Return<void> ret;
-        android::hardware::camera::common::V1_0::helper::CameraMetadata defaultSettings;
-        ret = session->constructDefaultRequestSettings(
-                RequestTemplate::PREVIEW, [&](auto status, const auto& req) {
-                    ASSERT_EQ(Status::OK, status);
-                    const camera_metadata_t* metadata =
-                            reinterpret_cast<const camera_metadata_t*>(req.data());
-                    defaultSettings = metadata;
-                    settings = req;
-                });
-        ASSERT_TRUE(ret.isOk());
-        android::status_t metadataRet = ::android::OK;
-        uint8_t videoStabilizationMode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
-        if (previewStabilizationOn) {
-            videoStabilizationMode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION;
-            metadataRet = defaultSettings.update(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
-                                                 &videoStabilizationMode, 1);
-        } else {
-            metadataRet = defaultSettings.update(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
-                                                 &videoStabilizationMode, 1);
-        }
-        ASSERT_EQ(metadataRet, ::android::OK);
-        hidl_handle buffer_handle;
-        StreamBuffer outputBuffer;
-        if (useHalBufManager) {
-            outputBuffer = {halStreamConfig.streams[0].id,
-                            /*bufferId*/ 0,
-                            buffer_handle,
-                            BufferStatus::OK,
-                            nullptr,
-                            nullptr};
-        } else {
-            allocateGraphicBuffer(
-                    testStream.width, testStream.height,
-                    /* We don't look at halStreamConfig.streams[0].consumerUsage
-                     * since that is 0 for output streams
-                     */
-                    android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
-                                                    GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
-                    halStreamConfig.streams[0].overrideFormat, &buffer_handle);
-            outputBuffer = {halStreamConfig.streams[0].id,
-                            bufferId,
-                            buffer_handle,
-                            BufferStatus::OK,
-                            nullptr,
-                            nullptr};
-        }
-        ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer};
-        StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
-        CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings, emptyInputBuffer,
-                                  outputBuffers};
-
-        {
-            std::unique_lock<std::mutex> l(mLock);
-            mInflightMap.clear();
-            mInflightMap.add(frameNumber, &inflightReq);
-        }
-
-        Status status = Status::INTERNAL_ERROR;
-        uint32_t numRequestProcessed = 0;
-        hidl_vec<BufferCache> cachesToRemove;
-        Return<void> returnStatus = session->processCaptureRequest(
-                {request}, cachesToRemove, [&status, &numRequestProcessed](auto s, uint32_t n) {
-                    status = s;
-                    numRequestProcessed = n;
-                });
-        ASSERT_TRUE(returnStatus.isOk());
-        ASSERT_EQ(Status::OK, status);
-        ASSERT_EQ(numRequestProcessed, 1u);
-
-        {
-            std::unique_lock<std::mutex> l(mLock);
-            while (!inflightReq.errorCodeValid &&
-                   ((0 < inflightReq.numBuffersLeft) || (!inflightReq.haveResultMetadata))) {
-                auto timeout = std::chrono::system_clock::now() +
-                               std::chrono::seconds(kStreamBufferTimeoutSec);
-                ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
-            }
-
-            ASSERT_FALSE(inflightReq.errorCodeValid);
-            ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
-            ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].buffer.streamId);
-            ASSERT_TRUE(inflightReq.shutterReadoutTimestampValid);
-            nsecs_t readoutTimestamp = inflightReq.shutterReadoutTimestamp;
-
-            if (previewStabilizationOn) {
-                // Here we collect the time difference between the buffer ready
-                // timestamp - notify readout timestamp.
-                // timeLag = buffer ready timestamp - notify readout timestamp.
-                // timeLag(previewStabilization) must be <=
-                //        timeLag(stabilization off) + 1 frame duration.
-                auto it = cameraDeviceToTimeLag.find(name.c_str());
-                camera_metadata_entry e;
-                e = inflightReq.collectedResult.find(ANDROID_SENSOR_FRAME_DURATION);
-                ASSERT_TRUE(e.count > 0);
-                nsecs_t frameDuration = e.data.i64[0];
-                ASSERT_TRUE(it != cameraDeviceToTimeLag.end());
-
-                nsecs_t previewStabOnLagTime =
-                        inflightReq.resultOutputBuffers[0].timeStamp - readoutTimestamp;
-                ASSERT_TRUE(previewStabOnLagTime <= (it->second + frameDuration));
-            } else {
-                // Fill in the buffer ready timestamp - notify timestamp;
-                cameraDeviceToTimeLag[std::string(name.c_str())] =
-                        inflightReq.resultOutputBuffers[0].timeStamp - readoutTimestamp;
-            }
-        }
-
-        if (useHalBufManager) {
-            verifyBuffersReturned(session, deviceVersion, testStream.id, cb);
-        }
-
-        ret = session->close();
-        ASSERT_TRUE(ret.isOk());
-    }
-}
-
 // Generate and verify a multi-camera capture request
 TEST_P(CameraHidlTest, processMultiCaptureRequestPreview) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
@@ -5771,188 +5319,6 @@
     }
 }
 
-// Generate and verify 10-bit dynamic range request
-TEST_P(CameraHidlTest, process10BitDynamicRangeRequest) {
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
-    uint64_t bufferId = 1;
-    uint32_t frameNumber = 1;
-    ::android::hardware::hidl_vec<uint8_t> settings;
-
-    for (const auto& name : cameraDeviceNames) {
-        int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_8) {
-            continue;
-        }
-        std::string version, deviceId;
-        ASSERT_TRUE(::matchDeviceName(name, mProviderType, &version, &deviceId));
-        camera_metadata_t* staticMeta;
-        Return<void> ret;
-        sp<ICameraDeviceSession> session;
-        openEmptyDeviceSession(name, mProvider, &session, &staticMeta);
-        if (!is10BitDynamicRangeCapable(staticMeta)) {
-            free_camera_metadata(staticMeta);
-            ret = session->close();
-            ASSERT_TRUE(ret.isOk());
-            continue;
-        }
-        std::vector<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap> profileList;
-        get10BitDynamicRangeProfiles(staticMeta, &profileList);
-        ASSERT_FALSE(profileList.empty());
-
-        android::hardware::camera::common::V1_0::helper::CameraMetadata defaultSettings;
-        ret = session->constructDefaultRequestSettings(
-                RequestTemplate::STILL_CAPTURE,
-                [&defaultSettings](auto status, const auto& req) mutable {
-                    ASSERT_EQ(Status::OK, status);
-
-                    const camera_metadata_t* metadata =
-                            reinterpret_cast<const camera_metadata_t*>(req.data());
-                    size_t expectedSize = req.size();
-                    int result = validate_camera_metadata_structure(metadata, &expectedSize);
-                    ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
-
-                    size_t entryCount = get_camera_metadata_entry_count(metadata);
-                    ASSERT_GT(entryCount, 0u);
-                    defaultSettings = metadata;
-                });
-        ASSERT_TRUE(ret.isOk());
-
-        const camera_metadata_t* settingsBuffer = defaultSettings.getAndLock();
-        settings.setToExternal(
-                reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(settingsBuffer)),
-                get_camera_metadata_size(settingsBuffer));
-        overrideRotateAndCrop(&settings);
-
-        free_camera_metadata(staticMeta);
-        ret = session->close();
-        ASSERT_TRUE(ret.isOk());
-        V3_6::HalStreamConfiguration halStreamConfig;
-        bool supportsPartialResults = false;
-        bool useHalBufManager = false;
-        uint32_t partialResultCount = 0;
-        V3_2::Stream previewStream;
-        sp<device::V3_8::ICameraDeviceSession> session3_8;
-        sp<DeviceCb> cb;
-        for (const auto& profile : profileList) {
-            configureStreams3_8(name, deviceVersion, mProvider, PixelFormat::IMPLEMENTATION_DEFINED,
-                                &session3_8, &previewStream, &halStreamConfig,
-                                &supportsPartialResults, &partialResultCount, &useHalBufManager,
-                                &cb, 0, /*maxResolution*/ false, profile);
-            ASSERT_NE(session3_8, nullptr);
-
-            std::shared_ptr<ResultMetadataQueue> resultQueue;
-            auto resultQueueRet = session3_8->getCaptureResultMetadataQueue(
-                    [&resultQueue](const auto& descriptor) {
-                        resultQueue = std::make_shared<ResultMetadataQueue>(descriptor);
-                        if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
-                            ALOGE("%s: HAL returns empty result metadata fmq,"
-                                  " not use it",
-                                  __func__);
-                            resultQueue = nullptr;
-                            // Don't use the queue onwards.
-                        }
-                    });
-            ASSERT_TRUE(resultQueueRet.isOk());
-
-            std::vector<hidl_handle> graphicBuffers;
-            graphicBuffers.reserve(halStreamConfig.streams.size());
-            ::android::hardware::hidl_vec<StreamBuffer> outputBuffers;
-            outputBuffers.resize(halStreamConfig.streams.size());
-            InFlightRequest inflightReq = {static_cast<ssize_t>(halStreamConfig.streams.size()),
-                                           false,
-                                           supportsPartialResults,
-                                           partialResultCount,
-                                           std::unordered_set<std::string>(),
-                                           resultQueue};
-
-            size_t k = 0;
-            for (const auto& halStream : halStreamConfig.streams) {
-                hidl_handle buffer_handle;
-                if (useHalBufManager) {
-                    outputBuffers[k] = {halStream.v3_4.v3_3.v3_2.id,
-                                        0,
-                                        buffer_handle,
-                                        BufferStatus::OK,
-                                        nullptr,
-                                        nullptr};
-                } else {
-                    allocateGraphicBuffer(
-                            previewStream.width, previewStream.height,
-                            android_convertGralloc1To0Usage(halStream.v3_4.v3_3.v3_2.producerUsage,
-                                                            halStream.v3_4.v3_3.v3_2.consumerUsage),
-                            halStream.v3_4.v3_3.v3_2.overrideFormat, &buffer_handle);
-
-                    graphicBuffers.push_back(buffer_handle);
-                    outputBuffers[k] = {halStream.v3_4.v3_3.v3_2.id,
-                                        bufferId,
-                                        buffer_handle,
-                                        BufferStatus::OK,
-                                        nullptr,
-                                        nullptr};
-                    bufferId++;
-                }
-                k++;
-            }
-
-            StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
-            V3_4::CaptureRequest request3_4;
-            request3_4.v3_2.frameNumber = frameNumber;
-            request3_4.v3_2.fmqSettingsSize = 0;
-            request3_4.v3_2.settings = settings;
-            request3_4.v3_2.inputBuffer = emptyInputBuffer;
-            request3_4.v3_2.outputBuffers = outputBuffers;
-            V3_7::CaptureRequest request3_7;
-            request3_7.v3_4 = request3_4;
-            request3_7.inputWidth = 0;
-            request3_7.inputHeight = 0;
-
-            {
-                std::unique_lock<std::mutex> l(mLock);
-                mInflightMap.clear();
-                mInflightMap.add(frameNumber, &inflightReq);
-            }
-
-            Status stat = Status::INTERNAL_ERROR;
-            uint32_t numRequestProcessed = 0;
-            hidl_vec<BufferCache> cachesToRemove;
-            Return<void> returnStatus = session3_8->processCaptureRequest_3_7(
-                    {request3_7}, cachesToRemove,
-                    [&stat, &numRequestProcessed](auto s, uint32_t n) {
-                        stat = s;
-                        numRequestProcessed = n;
-                    });
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OK, stat);
-            ASSERT_EQ(numRequestProcessed, 1u);
-
-            {
-                std::unique_lock<std::mutex> l(mLock);
-                while (!inflightReq.errorCodeValid &&
-                       ((0 < inflightReq.numBuffersLeft) || (!inflightReq.haveResultMetadata))) {
-                    auto timeout = std::chrono::system_clock::now() +
-                                   std::chrono::seconds(kStreamBufferTimeoutSec);
-                    ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
-                }
-
-                ASSERT_FALSE(inflightReq.errorCodeValid);
-                ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
-                verify10BitMetadata(mHandleImporter, inflightReq, profile);
-            }
-            if (useHalBufManager) {
-                hidl_vec<int32_t> streamIds(halStreamConfig.streams.size());
-                for (size_t i = 0; i < streamIds.size(); i++) {
-                    streamIds[i] = halStreamConfig.streams[i].v3_4.v3_3.v3_2.id;
-                }
-                session3_8->signalStreamFlush(streamIds, /*streamConfigCounter*/ 0);
-                cb->waitForBuffersReturned();
-            }
-
-            ret = session3_8->close();
-            ASSERT_TRUE(ret.isOk());
-        }
-    }
-}
-
 // Generate and verify a burst containing alternating sensor sensitivity values
 TEST_P(CameraHidlTest, processCaptureRequestBurstISO) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
@@ -5982,8 +5348,8 @@
         camera_metadata_entry_t hwLevel = staticMeta.find(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL);
         ASSERT_TRUE(0 < hwLevel.count);
         if (ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED == hwLevel.data.u8[0] ||
-                ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL == hwLevel.data.u8[0]) {
-            //Limited/External devices can skip this test
+            ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL == hwLevel.data.u8[0]) {
+            // Limited/External devices can skip this test
             ret = session->close();
             ASSERT_TRUE(ret.isOk());
             continue;
@@ -6946,134 +6312,6 @@
     }
 }
 
-// Verify that  valid stream use cases can be configured successfully, and invalid use cases
-// fail stream configuration.
-TEST_P(CameraHidlTest, configureStreamsUseCases) {
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
-
-    for (const auto& name : cameraDeviceNames) {
-        int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_8) {
-            continue;
-        }
-
-        camera_metadata_t* staticMeta;
-        Return<void> ret;
-        sp<ICameraDeviceSession> session;
-        sp<device::V3_3::ICameraDeviceSession> session3_3;
-        sp<device::V3_4::ICameraDeviceSession> session3_4;
-        sp<device::V3_5::ICameraDeviceSession> session3_5;
-        sp<device::V3_6::ICameraDeviceSession> session3_6;
-        sp<device::V3_7::ICameraDeviceSession> session3_7;
-        sp<device::V3_8::ICameraDeviceSession> session3_8;
-        sp<device::V3_2::ICameraDevice> cameraDevice;
-        sp<device::V3_5::ICameraDevice> cameraDevice3_5;
-        sp<device::V3_7::ICameraDevice> cameraDevice3_7;
-        sp<device::V3_8::ICameraDevice> cameraDevice3_8;
-        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
-                &cameraDevice /*out*/);
-        castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-                &session3_6, &session3_7, &session3_8);
-        ASSERT_NE(nullptr, session3_8);
-        castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
-                   &cameraDevice3_8);
-        ASSERT_NE(nullptr, cameraDevice3_8);
-
-        // Check if camera support depth only
-        if (isDepthOnly(staticMeta)) {
-            free_camera_metadata(staticMeta);
-            ret = session->close();
-            ASSERT_TRUE(ret.isOk());
-            continue;
-        }
-
-        std::vector<AvailableStream> outputPreviewStreams;
-        AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
-                static_cast<int32_t>(PixelFormat::YCBCR_420_888)};
-        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputPreviewStreams,
-                &previewThreshold));
-        ASSERT_NE(0u, outputPreviewStreams.size());
-
-        // Combine valid and invalid stream use cases
-        std::vector<int64_t> useCases(kMandatoryUseCases);
-        useCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL + 1);
-
-        std::vector<int64_t> supportedUseCases;
-        camera_metadata_ro_entry entry;
-        auto retcode = find_camera_metadata_ro_entry(staticMeta,
-                ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES, &entry);
-        if ((0 == retcode) && (entry.count > 0)) {
-            supportedUseCases.insert(supportedUseCases.end(), entry.data.i64,
-                    entry.data.i64 + entry.count);
-        } else {
-            supportedUseCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
-        }
-        free_camera_metadata(staticMeta);
-
-        ::android::hardware::hidl_vec<V3_8::Stream> streams3_8(1);
-        streams3_8[0].v3_7.groupId = -1;
-        streams3_8[0].v3_7.sensorPixelModesUsed = {
-                CameraMetadataEnumAndroidSensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT};
-        streams3_8[0].v3_7.v3_4.bufferSize = 0;
-        streams3_8[0].v3_7.v3_4.v3_2.id = 0;
-        streams3_8[0].v3_7.v3_4.v3_2.streamType = StreamType::OUTPUT;
-        streams3_8[0].v3_7.v3_4.v3_2.width = static_cast<uint32_t>(outputPreviewStreams[0].width);
-        streams3_8[0].v3_7.v3_4.v3_2.height = static_cast<uint32_t>(outputPreviewStreams[0].height);
-        streams3_8[0].v3_7.v3_4.v3_2.format =
-                static_cast<PixelFormat>(outputPreviewStreams[0].format);
-        streams3_8[0].v3_7.v3_4.v3_2.usage = GRALLOC1_CONSUMER_USAGE_CPU_READ;
-        streams3_8[0].v3_7.v3_4.v3_2.dataSpace = 0;
-        streams3_8[0].v3_7.v3_4.v3_2.rotation = StreamRotation::ROTATION_0;
-        streams3_8[0].dynamicRangeProfile =
-                static_cast<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap>(
-                        ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
-
-        uint32_t streamConfigCounter = 0;
-        ::android::hardware::camera::device::V3_8::StreamConfiguration config3_8;
-        RequestTemplate reqTemplate = RequestTemplate::STILL_CAPTURE;
-        ret = session3_8->constructDefaultRequestSettings(reqTemplate,
-                                        [&config3_8](auto status, const auto& req) {
-                                                    ASSERT_EQ(Status::OK, status);
-                                                    config3_8.sessionParams = req;
-                                                });
-        ASSERT_TRUE(ret.isOk());
-
-        for (int64_t useCase : useCases) {
-            bool useCaseSupported = std::find(supportedUseCases.begin(),
-                    supportedUseCases.end(), useCase) != supportedUseCases.end();
-
-            streams3_8[0].useCase =
-                    static_cast<CameraMetadataEnumAndroidScalerAvailableStreamUseCases>(useCase);
-            config3_8.streams = streams3_8;
-            config3_8.operationMode = StreamConfigurationMode::NORMAL_MODE;
-            config3_8.streamConfigCounter = streamConfigCounter;
-            config3_8.multiResolutionInputImage = false;
-            ret = cameraDevice3_8->isStreamCombinationSupported_3_8(
-                    config3_8, [&useCaseSupported](Status s, bool combStatus) {
-                        ASSERT_TRUE((Status::OK == s) || (Status::METHOD_NOT_SUPPORTED == s));
-                        if (Status::OK == s) {
-                            ASSERT_EQ(combStatus, useCaseSupported);
-                        }
-                    });
-            ASSERT_TRUE(ret.isOk());
-
-            ret = session3_8->configureStreams_3_8(
-                              config3_8,
-                              [&](Status s, device::V3_6::HalStreamConfiguration halConfig) {
-                                  if (useCaseSupported) {
-                                      ASSERT_EQ(Status::OK, s);
-                                      ASSERT_EQ(1u, halConfig.streams.size());
-                                  } else {
-                                      ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                                  }
-                              });
-            ASSERT_TRUE(ret.isOk());
-        }
-        ret = session3_8->close();
-        ASSERT_TRUE(ret.isOk());
-    }
-}
-
 // Retrieve all valid output stream resolutions from the camera
 // static characteristics.
 Status CameraHidlTest::getAvailableOutputStreams(const camera_metadata_t* staticMeta,
@@ -7736,9 +6974,8 @@
     sp<device::V3_4::ICameraDeviceSession> session3_4;
     sp<device::V3_5::ICameraDeviceSession> session3_5;
     sp<device::V3_6::ICameraDeviceSession> session3_6;
-    sp<device::V3_8::ICameraDeviceSession> session3_8;
     castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
-                session3_7, &session3_8);
+                session3_7);
     ASSERT_NE(nullptr, (*session3_7).get());
 
     *useHalBufManager = false;
@@ -7786,8 +7023,7 @@
     ASSERT_TRUE(deviceVersion >= CAMERA_DEVICE_API_VERSION_3_7);
     sp<device::V3_5::ICameraDevice> cameraDevice3_5 = nullptr;
     sp<device::V3_7::ICameraDevice> cameraDevice3_7 = nullptr;
-    sp<device::V3_8::ICameraDevice> cameraDevice3_8 = nullptr;
-    castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7, &cameraDevice3_8);
+    castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
     ASSERT_NE(cameraDevice3_7, nullptr);
     bool supported = false;
     ret = cameraDevice3_7->isStreamCombinationSupported_3_7(
@@ -7820,153 +7056,6 @@
     ASSERT_TRUE(ret.isOk());
 }
 
-// Configure streams
-void CameraHidlTest::configureStreams3_8(
-        const std::string& name, int32_t deviceVersion, sp<ICameraProvider> provider,
-        PixelFormat format, sp<device::V3_8::ICameraDeviceSession>* session3_8 /*out*/,
-        V3_2::Stream* previewStream /*out*/,
-        device::V3_6::HalStreamConfiguration* halStreamConfig /*out*/,
-        bool* supportsPartialResults /*out*/, uint32_t* partialResultCount /*out*/,
-        bool* useHalBufManager /*out*/, sp<DeviceCb>* outCb /*out*/, uint32_t streamConfigCounter,
-        bool maxResolution,
-        CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap prof) {
-    ASSERT_NE(nullptr, session3_8);
-    ASSERT_NE(nullptr, halStreamConfig);
-    ASSERT_NE(nullptr, previewStream);
-    ASSERT_NE(nullptr, supportsPartialResults);
-    ASSERT_NE(nullptr, partialResultCount);
-    ASSERT_NE(nullptr, useHalBufManager);
-    ASSERT_NE(nullptr, outCb);
-    ASSERT_TRUE(deviceVersion >= CAMERA_DEVICE_API_VERSION_3_8);
-
-    std::vector<AvailableStream> outputStreams;
-    ::android::sp<ICameraDevice> device3_x;
-    ALOGI("configureStreams: Testing camera device %s", name.c_str());
-    Return<void> ret;
-    ret = provider->getCameraDeviceInterface_V3_x(name, [&](auto status, const auto& device) {
-        ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
-        ASSERT_EQ(Status::OK, status);
-        ASSERT_NE(device, nullptr);
-        device3_x = device;
-    });
-    ASSERT_TRUE(ret.isOk());
-
-    camera_metadata_t* staticMeta;
-    ret = device3_x->getCameraCharacteristics([&](Status s, CameraMetadata metadata) {
-        ASSERT_EQ(Status::OK, s);
-        staticMeta =
-                clone_camera_metadata(reinterpret_cast<const camera_metadata_t*>(metadata.data()));
-        ASSERT_NE(nullptr, staticMeta);
-    });
-    ASSERT_TRUE(ret.isOk());
-
-    camera_metadata_ro_entry entry;
-    auto status =
-            find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry);
-    if ((0 == status) && (entry.count > 0)) {
-        *partialResultCount = entry.data.i32[0];
-        *supportsPartialResults = (*partialResultCount > 1);
-    }
-
-    sp<DeviceCb> cb = new DeviceCb(this, deviceVersion, staticMeta);
-    sp<ICameraDeviceSession> session;
-    ret = device3_x->open(cb, [&session](auto status, const auto& newSession) {
-        ALOGI("device::open returns status:%d", (int)status);
-        ASSERT_EQ(Status::OK, status);
-        ASSERT_NE(newSession, nullptr);
-        session = newSession;
-    });
-    ASSERT_TRUE(ret.isOk());
-    *outCb = cb;
-
-    sp<device::V3_3::ICameraDeviceSession> session3_3;
-    sp<device::V3_4::ICameraDeviceSession> session3_4;
-    sp<device::V3_5::ICameraDeviceSession> session3_5;
-    sp<device::V3_6::ICameraDeviceSession> session3_6;
-    sp<device::V3_7::ICameraDeviceSession> session3_7;
-    castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
-                &session3_7, session3_8);
-    ASSERT_NE(nullptr, (*session3_8).get());
-
-    *useHalBufManager = false;
-    status = find_camera_metadata_ro_entry(
-            staticMeta, ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
-    if ((0 == status) && (entry.count == 1)) {
-        *useHalBufManager = (entry.data.u8[0] ==
-                             ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
-    }
-
-    outputStreams.clear();
-    Size maxSize;
-    auto rc = getMaxOutputSizeForFormat(staticMeta, format, &maxSize, maxResolution);
-    ASSERT_EQ(Status::OK, rc);
-    free_camera_metadata(staticMeta);
-
-    ::android::hardware::hidl_vec<V3_8::Stream> streams3_8(1);
-    streams3_8[0].v3_7.groupId = -1;
-    streams3_8[0].v3_7.sensorPixelModesUsed = {
-            CameraMetadataEnumAndroidSensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT};
-    streams3_8[0].v3_7.v3_4.bufferSize = 0;
-    streams3_8[0].v3_7.v3_4.v3_2.id = 0;
-    streams3_8[0].v3_7.v3_4.v3_2.streamType = StreamType::OUTPUT;
-    streams3_8[0].v3_7.v3_4.v3_2.width = static_cast<uint32_t>(maxSize.width);
-    streams3_8[0].v3_7.v3_4.v3_2.height = static_cast<uint32_t>(maxSize.height);
-    streams3_8[0].v3_7.v3_4.v3_2.format = static_cast<PixelFormat>(format);
-    streams3_8[0].v3_7.v3_4.v3_2.usage = GRALLOC1_CONSUMER_USAGE_CPU_READ;
-    streams3_8[0].v3_7.v3_4.v3_2.dataSpace = 0;
-    streams3_8[0].v3_7.v3_4.v3_2.rotation = StreamRotation::ROTATION_0;
-    streams3_8[0].dynamicRangeProfile = prof;
-
-    ::android::hardware::camera::device::V3_8::StreamConfiguration config3_8;
-    config3_8.streams = streams3_8;
-    config3_8.operationMode = StreamConfigurationMode::NORMAL_MODE;
-    config3_8.streamConfigCounter = streamConfigCounter;
-    config3_8.multiResolutionInputImage = false;
-    RequestTemplate reqTemplate = RequestTemplate::STILL_CAPTURE;
-    ret = (*session3_8)
-                  ->constructDefaultRequestSettings(reqTemplate,
-                                                    [&config3_8](auto status, const auto& req) {
-                                                        ASSERT_EQ(Status::OK, status);
-                                                        config3_8.sessionParams = req;
-                                                    });
-    ASSERT_TRUE(ret.isOk());
-
-    sp<device::V3_5::ICameraDevice> cameraDevice3_5 = nullptr;
-    sp<device::V3_7::ICameraDevice> cameraDevice3_7 = nullptr;
-    sp<device::V3_8::ICameraDevice> cameraDevice3_8 = nullptr;
-    castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7, &cameraDevice3_8);
-    ASSERT_NE(cameraDevice3_8, nullptr);
-    bool supported = false;
-    ret = cameraDevice3_8->isStreamCombinationSupported_3_8(
-            config3_8, [&supported](Status s, bool combStatus) {
-                ASSERT_TRUE((Status::OK == s) || (Status::METHOD_NOT_SUPPORTED == s));
-                if (Status::OK == s) {
-                    supported = combStatus;
-                }
-            });
-    ASSERT_TRUE(ret.isOk());
-    ASSERT_EQ(supported, true);
-
-    if (*session3_8 != nullptr) {
-        ret = (*session3_8)
-                      ->configureStreams_3_8(
-                              config3_8,
-                              [&](Status s, device::V3_6::HalStreamConfiguration halConfig) {
-                                  ASSERT_EQ(Status::OK, s);
-                                  *halStreamConfig = halConfig;
-                                  if (*useHalBufManager) {
-                                      hidl_vec<V3_4::Stream> streams(1);
-                                      hidl_vec<V3_2::HalStream> halStreams(1);
-                                      streams[0] = streams3_8[0].v3_7.v3_4;
-                                      halStreams[0] = halConfig.streams[0].v3_4.v3_3.v3_2;
-                                      cb->setCurrentStreamConfig(streams, halStreams);
-                                  }
-                              });
-    }
-    *previewStream = streams3_8[0].v3_7.v3_4.v3_2;
-    ASSERT_TRUE(ret.isOk());
-}
-
 // Configure multiple preview streams using different physical ids.
 void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
         sp<ICameraProvider> provider,
@@ -8041,9 +7130,8 @@
     sp<device::V3_3::ICameraDeviceSession> session3_3;
     sp<device::V3_6::ICameraDeviceSession> session3_6;
     sp<device::V3_7::ICameraDeviceSession> session3_7;
-    sp<device::V3_8::ICameraDeviceSession> session3_8;
-    castSession(session, deviceVersion, &session3_3, session3_4, session3_5,
-            &session3_6, &session3_7, &session3_8);
+    castSession(session, deviceVersion, &session3_3, session3_4, session3_5, &session3_6,
+                &session3_7);
     ASSERT_NE(nullptr, (*session3_4).get());
 
     *useHalBufManager = false;
@@ -8088,8 +7176,7 @@
     if (allowUnsupport) {
         sp<device::V3_5::ICameraDevice> cameraDevice3_5;
         sp<device::V3_7::ICameraDevice> cameraDevice3_7;
-        sp<device::V3_8::ICameraDevice> cameraDevice3_8;
-        castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7, &cameraDevice3_8);
+        castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
 
         bool supported = false;
         ret = cameraDevice3_5->isStreamCombinationSupported(config3_4,
@@ -8282,95 +7369,6 @@
     return false;
 }
 
-void CameraHidlTest::get10BitDynamicRangeProfiles(const camera_metadata_t* staticMeta,
-        std::vector<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap> *profiles) {
-    ASSERT_NE(nullptr, staticMeta);
-    ASSERT_NE(nullptr, profiles);
-    camera_metadata_ro_entry entry;
-    std::unordered_set<int64_t> entries;
-    int rc = find_camera_metadata_ro_entry(staticMeta,
-            ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP, &entry);
-    ASSERT_EQ(rc, 0);
-    ASSERT_TRUE(entry.count > 0);
-    ASSERT_EQ(entry.count % 3, 0);
-
-    for (uint32_t i = 0; i < entry.count; i += 3) {
-        ASSERT_NE(entry.data.i64[i],
-                ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
-        ASSERT_EQ(entries.find(entry.data.i64[i]), entries.end());
-        entries.insert(entry.data.i64[i]);
-        profiles->emplace_back(
-                static_cast<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap>
-                (entry.data.i64[i]));
-    }
-
-    if (!entries.empty()) {
-        ASSERT_NE(entries.find(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10),
-                entries.end());
-    }
-}
-
-bool CameraHidlTest::is10BitDynamicRangeCapable(const camera_metadata_t* staticMeta) {
-    camera_metadata_ro_entry scalarEntry;
-    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
-                                           &scalarEntry);
-    if (rc == 0) {
-        for (uint32_t i = 0; i < scalarEntry.count; i++) {
-            if (scalarEntry.data.u8[i] ==
-                ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
-void CameraHidlTest::verify10BitMetadata(HandleImporter& importer,
-        const InFlightRequest& request,
-        CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap profile) {
-    for (const auto& b : request.resultOutputBuffers) {
-        bool smpte2086Present = importer.isSmpte2086Present(b.buffer.buffer.getNativeHandle());
-        bool smpte2094_10Present = importer.isSmpte2094_10Present(
-                b.buffer.buffer.getNativeHandle());
-        bool smpte2094_40Present = importer.isSmpte2094_40Present(
-                b.buffer.buffer.getNativeHandle());
-
-        switch (static_cast<int64_t>(profile)) {
-            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10:
-                ASSERT_FALSE(smpte2086Present);
-                ASSERT_FALSE(smpte2094_10Present);
-                ASSERT_FALSE(smpte2094_40Present);
-                break;
-            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10:
-                ASSERT_TRUE(smpte2086Present);
-                ASSERT_FALSE(smpte2094_10Present);
-                ASSERT_FALSE(smpte2094_40Present);
-                break;
-            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS:
-                ASSERT_FALSE(smpte2086Present);
-                ASSERT_FALSE(smpte2094_10Present);
-                ASSERT_TRUE(smpte2094_40Present);
-                break;
-            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF:
-            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO:
-            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM:
-            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO:
-            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF:
-            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO:
-            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM:
-            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO:
-                ASSERT_FALSE(smpte2086Present);
-                ASSERT_TRUE(smpte2094_10Present);
-                ASSERT_FALSE(smpte2094_40Present);
-                break;
-            default:
-                ALOGE("%s: Unexpected 10-bit dynamic range profile: %" PRId64,
-                        __FUNCTION__, profile);
-                ADD_FAILURE();
-        }
-    }
-}
-
 bool CameraHidlTest::isDepthOnly(const camera_metadata_t* staticMeta) {
     camera_metadata_ro_entry scalarEntry;
     camera_metadata_ro_entry depthEntry;
@@ -8534,9 +7532,8 @@
     sp<device::V3_5::ICameraDeviceSession> session3_5;
     sp<device::V3_6::ICameraDeviceSession> session3_6;
     sp<device::V3_7::ICameraDeviceSession> session3_7;
-    sp<device::V3_8::ICameraDeviceSession> session3_8;
-    castSession(*session, deviceVersion, &session3_3, &session3_4, &session3_5,
-            &session3_6, &session3_7, &session3_8);
+    castSession(*session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+                &session3_7);
 
     *useHalBufManager = false;
     status = find_camera_metadata_ro_entry(staticMeta,
@@ -8667,19 +7664,11 @@
 void CameraHidlTest::castDevice(const sp<device::V3_2::ICameraDevice>& device,
                                 int32_t deviceVersion,
                                 sp<device::V3_5::ICameraDevice>* device3_5 /*out*/,
-                                sp<device::V3_7::ICameraDevice>* device3_7 /*out*/,
-                                sp<device::V3_8::ICameraDevice>* device3_8 /*out*/) {
+                                sp<device::V3_7::ICameraDevice>* device3_7 /*out*/) {
     ASSERT_NE(nullptr, device3_5);
     ASSERT_NE(nullptr, device3_7);
-    ASSERT_NE(nullptr, device3_8);
 
     switch (deviceVersion) {
-        case CAMERA_DEVICE_API_VERSION_3_8: {
-            auto castResult = device::V3_8::ICameraDevice::castFrom(device);
-            ASSERT_TRUE(castResult.isOk());
-            *device3_8 = castResult;
-        }
-            [[fallthrough]];
         case CAMERA_DEVICE_API_VERSION_3_7: {
             auto castResult = device::V3_7::ICameraDevice::castFrom(device);
             ASSERT_TRUE(castResult.isOk());
@@ -8723,27 +7712,19 @@
 }
 
 //Cast camera device session to corresponding version
-void CameraHidlTest::castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
-        sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
-        sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
-        sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/,
-        sp<device::V3_6::ICameraDeviceSession> *session3_6 /*out*/,
-        sp<device::V3_7::ICameraDeviceSession> *session3_7 /*out*/,
-        sp<device::V3_8::ICameraDeviceSession> *session3_8 /*out*/) {
+void CameraHidlTest::castSession(const sp<ICameraDeviceSession>& session, int32_t deviceVersion,
+                                 sp<device::V3_3::ICameraDeviceSession>* session3_3 /*out*/,
+                                 sp<device::V3_4::ICameraDeviceSession>* session3_4 /*out*/,
+                                 sp<device::V3_5::ICameraDeviceSession>* session3_5 /*out*/,
+                                 sp<device::V3_6::ICameraDeviceSession>* session3_6 /*out*/,
+                                 sp<device::V3_7::ICameraDeviceSession>* session3_7 /*out*/) {
     ASSERT_NE(nullptr, session3_3);
     ASSERT_NE(nullptr, session3_4);
     ASSERT_NE(nullptr, session3_5);
     ASSERT_NE(nullptr, session3_6);
     ASSERT_NE(nullptr, session3_7);
-    ASSERT_NE(nullptr, session3_8);
 
     switch (deviceVersion) {
-        case CAMERA_DEVICE_API_VERSION_3_8: {
-            auto castResult = device::V3_8::ICameraDeviceSession::castFrom(session);
-            ASSERT_TRUE(castResult.isOk());
-            *session3_8 = castResult;
-        }
-        [[fallthrough]];
         case CAMERA_DEVICE_API_VERSION_3_7: {
             auto castResult = device::V3_7::ICameraDeviceSession::castFrom(session);
             ASSERT_TRUE(castResult.isOk());
@@ -9661,9 +8642,8 @@
     sp<device::V3_5::ICameraDeviceSession> session3_5;
     sp<device::V3_6::ICameraDeviceSession> session3_6;
     sp<device::V3_7::ICameraDeviceSession> session3_7;
-    sp<device::V3_8::ICameraDeviceSession> session3_8;
-    castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
-            &session3_6, &session3_7, &session3_8);
+    castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+                &session3_7);
     ASSERT_NE(nullptr, session3_5.get());
 
     hidl_vec<int32_t> streamIds(1);
@@ -9905,7 +8885,7 @@
     size_t CONFIG_ENTRY_TYPE_OFFSET = 3;
     size_t CONFIG_ENTRY_BITFIELD_OFFSET = 4;
     uint32_t maxPublicUsecase =
-            ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END_3_8;
+            ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END;
     uint32_t vendorUsecaseStart =
             ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VENDOR_START;
     uint32_t usecaseMask = (1 << vendorUsecaseStart) - 1;
diff --git a/camera/provider/aidl/Android.bp b/camera/provider/aidl/Android.bp
index f082bce..87a94b2 100644
--- a/camera/provider/aidl/Android.bp
+++ b/camera/provider/aidl/Android.bp
@@ -25,11 +25,6 @@
         cpp: {
             enabled: false,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index 462698c..fe03732 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -39,7 +39,7 @@
 using ::aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap;
 using ::aidl::android::hardware::camera::metadata::SensorPixelMode;
 using ::aidl::android::hardware::camera::provider::CameraIdAndStreamCombination;
-using ::aidl::android::hardware::camera::provider::ICameraProviderCallbackDefault;
+using ::aidl::android::hardware::camera::provider::BnCameraProviderCallback;
 
 using ::ndk::ScopedAStatus;
 
@@ -86,7 +86,7 @@
 
 // Test if ICameraProvider::setCallback returns Status::OK
 TEST_P(CameraAidlTest, setCallback) {
-    struct ProviderCb : public ICameraProviderCallbackDefault {
+    struct ProviderCb : public BnCameraProviderCallback {
         ScopedAStatus cameraDeviceStatusChange(const std::string& cameraDeviceName,
                                                CameraDeviceStatus newStatus) override {
             ALOGI("camera device status callback name %s, status %d", cameraDeviceName.c_str(),
@@ -109,11 +109,11 @@
         }
     };
 
-    std::shared_ptr<ProviderCb> cb = ProviderCb::make<ProviderCb>();
+    std::shared_ptr<ProviderCb> cb = ndk::SharedRefBase::make<ProviderCb>();
     ScopedAStatus ret = mProvider->setCallback(cb);
     ASSERT_TRUE(ret.isOk());
     ret = mProvider->setCallback(nullptr);
-    ASSERT_TRUE(ret.isOk());
+    ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT), ret.getServiceSpecificError());
 }
 
 // Test if ICameraProvider::getCameraDeviceInterface returns Status::OK and non-null device
@@ -399,9 +399,6 @@
             }
         }
     }
-
-    ret = mProvider->setCallback(nullptr);
-    ASSERT_TRUE(ret.isOk());
 }
 
 // Check dump functionality.
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index fd83e37..c11fc0c 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -55,26 +55,6 @@
 using ::ndk::SpAIBinder;
 
 namespace {
-bool matchDeviceName(const std::string& deviceName, const std::string& providerType,
-                     std::string* deviceVersion, std::string* cameraId) {
-    // expected format: device@<major>.<minor>/<type>/<id>
-    std::stringstream pattern;
-    pattern << "device@[0-9]+\\.[0-9]+/" << providerType << "/(.+)";
-    std::regex e(pattern.str());
-
-    std::smatch sm;
-    if (std::regex_match(deviceName, sm, e)) {
-        if (deviceVersion != nullptr) {
-            *deviceVersion = sm[1];
-        }
-        if (cameraId != nullptr) {
-            *cameraId = sm[2];
-        }
-        return true;
-    }
-    return false;
-}
-
 bool parseProviderName(const std::string& serviceDescriptor, std::string* type /*out*/,
                        uint32_t* id /*out*/) {
     if (!type || !id) {
@@ -498,13 +478,11 @@
 
 bool CameraAidlTest::matchDeviceName(const std::string& deviceName, const std::string& providerType,
                                      std::string* deviceVersion, std::string* cameraId) {
-    // "device@<version>/legacy/<id>"
-    std::string pattern;
-    pattern.append("device@([0-9]+\\.[0-9]+)/");
-    pattern.append(providerType);
-    pattern.append("/(.+)");
+    // expected format: device@<major>.<minor>/<type>/<id>
+    std::stringstream pattern;
+    pattern << "device@([0-9]+\\.[0-9]+)/" << providerType << "/(.+)";
+    std::regex e(pattern.str());
 
-    std::regex e(pattern);
     std::smatch sm;
     if (std::regex_match(deviceName, sm, e)) {
         if (deviceVersion != nullptr) {
@@ -1160,7 +1138,7 @@
     }
 
     std::string version, cameraId;
-    ASSERT_TRUE(::matchDeviceName(cameraName, mProviderType, &version, &cameraId));
+    ASSERT_TRUE(matchDeviceName(cameraName, mProviderType, &version, &cameraId));
     std::unordered_set<std::string> physicalIds;
     rc = getPhysicalCameraIds(metadata, &physicalIds);
     ASSERT_TRUE(isUltraHighResCamera || Status::OK == rc);
@@ -1192,7 +1170,7 @@
         SystemCameraKind physSystemCameraKind = SystemCameraKind::PUBLIC;
         for (auto& deviceName : deviceNames) {
             std::string publicVersion, publicId;
-            ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, &publicVersion, &publicId));
+            ASSERT_TRUE(matchDeviceName(deviceName, mProviderType, &publicVersion, &publicId));
             if (physicalId == publicId) {
                 isPublicId = true;
                 fullPublicId = deviceName;
diff --git a/compatibility_matrices/compatibility_matrix.3.xml b/compatibility_matrices/compatibility_matrix.3.xml
index 468735d..0964c99 100644
--- a/compatibility_matrices/compatibility_matrix.3.xml
+++ b/compatibility_matrices/compatibility_matrix.3.xml
@@ -183,7 +183,10 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
+    <!-- Either the AIDL or the HIDL allocator HAL must exist on the device.
+         If the HIDL composer HAL exists, it must be at least version 2.0.
+         See DeviceManifestTest.GrallocHal -->
+    <hal format="hidl" optional="true">
         <name>android.hardware.graphics.allocator</name>
         <version>2.0</version>
         <interface>
diff --git a/compatibility_matrices/compatibility_matrix.4.xml b/compatibility_matrices/compatibility_matrix.4.xml
index 96f291f..8ef0b3a 100644
--- a/compatibility_matrices/compatibility_matrix.4.xml
+++ b/compatibility_matrices/compatibility_matrix.4.xml
@@ -187,7 +187,10 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
+    <!-- Either the AIDL or the HIDL allocator HAL must exist on the device.
+         If the HIDL composer HAL exists, it must be at least version 2.0.
+         See DeviceManifestTest.GrallocHal -->
+    <hal format="hidl" optional="true">
         <name>android.hardware.graphics.allocator</name>
         <version>2.0</version>
         <version>3.0</version>
diff --git a/compatibility_matrices/compatibility_matrix.5.xml b/compatibility_matrices/compatibility_matrix.5.xml
index 3642814..12b85c7 100644
--- a/compatibility_matrices/compatibility_matrix.5.xml
+++ b/compatibility_matrices/compatibility_matrix.5.xml
@@ -208,7 +208,10 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
+    <!-- Either the AIDL or the HIDL allocator HAL must exist on the device.
+         If the HIDL composer HAL exists, it must be at least version 2.0.
+         See DeviceManifestTest.GrallocHal -->
+    <hal format="hidl" optional="true">
         <name>android.hardware.graphics.allocator</name>
         <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
         <version>2.0</version>
diff --git a/compatibility_matrices/compatibility_matrix.6.xml b/compatibility_matrices/compatibility_matrix.6.xml
index 9c42cb0..e19d2dd 100644
--- a/compatibility_matrices/compatibility_matrix.6.xml
+++ b/compatibility_matrices/compatibility_matrix.6.xml
@@ -238,7 +238,10 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
+    <!-- Either the AIDL or the HIDL allocator HAL must exist on the device.
+         If the HIDL composer HAL exists, it must be at least version 2.0.
+         See DeviceManifestTest.GrallocHal -->
+    <hal format="hidl" optional="true">
         <name>android.hardware.graphics.allocator</name>
         <!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
         <version>2.0</version>
diff --git a/compatibility_matrices/compatibility_matrix.7.xml b/compatibility_matrices/compatibility_matrix.7.xml
index acee459..26b8d63 100644
--- a/compatibility_matrices/compatibility_matrix.7.xml
+++ b/compatibility_matrices/compatibility_matrix.7.xml
@@ -142,6 +142,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.bluetooth.audio</name>
+        <version>2</version>
         <interface>
             <name>IBluetoothAudioProviderFactory</name>
             <instance>default</instance>
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 3e4588f..386db52 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -155,6 +155,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.bluetooth.audio</name>
+        <version>2</version>
         <interface>
             <name>IBluetoothAudioProviderFactory</name>
             <instance>default</instance>
@@ -168,6 +169,13 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.boot</name>
+        <interface>
+            <name>IBootControl</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.broadcastradio</name>
         <version>1.0-1</version>
@@ -290,9 +298,13 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <!-- Either the AIDL or the HIDL allocator HAL must exist on the device.
+         If the HIDL composer HAL exists, it must be at least version 2.0.
+         See DeviceManifestTest.GrallocHal -->
     <hal format="hidl" optional="true">
         <name>android.hardware.graphics.allocator</name>
-        <!-- New, non-Go devices should use 4.0 or the AIDL hal. -->
+        <!-- New, non-Go devices should use 4.0 or the AIDL hal.
+             See DeviceManifestTest.GrallocVersionCompatibility. -->
         <version>2.0</version>
         <version>3.0</version>
         <version>4.0</version>
diff --git a/confirmationui/support/Android.bp b/confirmationui/support/Android.bp
index 6ab83f2..1200115 100644
--- a/confirmationui/support/Android.bp
+++ b/confirmationui/support/Android.bp
@@ -36,7 +36,7 @@
     ],
     export_include_dirs: [
         "include",
-    ]
+    ],
 }
 
 cc_test {
@@ -56,6 +56,5 @@
         "libhidlbase",
     ],
     test_suites: ["general-tests"],
-    clang: true,
-    cflags: [ "-O0" ],
+    cflags: ["-O0"],
 }
diff --git a/current.txt b/current.txt
index ce03b55..afde7b1 100644
--- a/current.txt
+++ b/current.txt
@@ -5,6 +5,7 @@
 
 717c17cd380bb48710dff601d1a03351d4ebc28028353d5d60489248f506523c android.hardware.tests.lazy@1.0::ILazy
 67222a2ed4071b6c232e671ce0f4be4f85c1c6fb017ec2355396adaae1fe26be android.hardware.tests.lazy@1.1::ILazy
+c1c5fbd3a81c0d190c89348eed39539c77e97fe1d8d1b9874eba56393e70c6f0 android.hardware.tests.lazy_cb@1.0::ILazyCb
 
 # HALs released in Android O
 
@@ -919,5 +920,13 @@
 ec11690878547a55eb1d6a286f83e227d8328c2cf1d069316b55b4e4084fd9a2 android.hardware.audio@7.1::IStreamOut
 786b8619580d7cfae70f02136307e141481714fcc76c6b700e655568f1bf0733 android.hardware.audio@7.1::IStreamOutLatencyModeCallback
 bfbf383768881eb06f99db76ce79135e37b2b105a90d67bf7468f8df05180bf4 android.hardware.audio@7.1::types
+1de444305084b815a1cf45b41d8bd7fa8dc960da89c2d548f38feaa662d8f310 android.hardware.wifi@1.6::IWifi
+e8cf2570d2f3d8cf7a7251e85a87cbf633d0bff3c28e1c9bbf339dea04b254fa android.hardware.wifi@1.6::IWifiChip
+e05c047de0a7f2cc8f166a1c808b78e8565ff866fb69991fc3bbfa9141871d5b android.hardware.wifi@1.6::IWifiNanIface
+b7ce2d87841585551b082fca6d099622e63b7099e0d8013f687ea1a1dc35c4dc android.hardware.wifi@1.6::IWifiNanIfaceEventCallback
+8c51742b2540b005edb16d2003b87f8e8220e113b234ddbb133f95e86837e9aa android.hardware.wifi@1.6::IWifiRttController
+537f0bcfaf9d91b3136984f5e85d6ea559771726d6624a1d17c151b9c9f4b2f9 android.hardware.wifi@1.6::IWifiRttControllerEventCallback
+1bac6a7c8136dfb0414fe5639eec115aa2d12927e64a0642a43fb53225f099b2 android.hardware.wifi@1.6::IWifiStaIface
+0a800e010e8eb6eecdfdc96f04fd2ae2f417a79a74a7c0eec3a9f539199bccd4 android.hardware.wifi@1.6::types
 
 # There will be no more HIDL HALs. Use AIDL instead.
diff --git a/drm/aidl/Android.bp b/drm/aidl/Android.bp
index 0fdba31..6273a38 100644
--- a/drm/aidl/Android.bp
+++ b/drm/aidl/Android.bp
@@ -23,9 +23,6 @@
             sdk_version: "module_current",
         },
         ndk: {
-            vndk: {
-                enabled: true,
-            },
             min_sdk_version: "current",
         },
     },
diff --git a/drm/aidl/vts/drm_hal_common.cpp b/drm/aidl/vts/drm_hal_common.cpp
index de7dc28..7de8167 100644
--- a/drm/aidl/vts/drm_hal_common.cpp
+++ b/drm/aidl/vts/drm_hal_common.cpp
@@ -73,6 +73,7 @@
 }
 
 const char* kDrmIface = "android.hardware.drm.IDrmFactory";
+const int MAX_OPEN_SESSION_ATTEMPTS = 3;
 
 std::string HalFullName(const std::string& iface, const std::string& basename) {
     return iface + '/' + basename;
@@ -328,9 +329,19 @@
  */
 SessionId DrmHalTest::openSession() {
     SessionId sessionId;
-    auto ret = drmPlugin->openSession(SecurityLevel::DEFAULT, &sessionId);
-    EXPECT_OK(ret);
-    EXPECT_NE(0u, sessionId.size());
+
+    int attmpt = 0;
+    while (attmpt++ < MAX_OPEN_SESSION_ATTEMPTS) {
+        auto ret = drmPlugin->openSession(SecurityLevel::DEFAULT, &sessionId);
+        if(DrmErr(ret) == Status::ERROR_DRM_NOT_PROVISIONED) {
+            provision();
+        } else {
+            EXPECT_OK(ret);
+            EXPECT_NE(0u, sessionId.size());
+            break;
+        }
+    }
+
     return sessionId;
 }
 
diff --git a/dumpstate/aidl/Android.bp b/dumpstate/aidl/Android.bp
index d9acc7a..63670bb 100644
--- a/dumpstate/aidl/Android.bp
+++ b/dumpstate/aidl/Android.bp
@@ -33,11 +33,6 @@
         java: {
             enabled: false,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
diff --git a/gnss/aidl/Android.bp b/gnss/aidl/Android.bp
index 9f9090c..f45fe5d 100644
--- a/gnss/aidl/Android.bp
+++ b/gnss/aidl/Android.bp
@@ -36,11 +36,6 @@
         java: {
             platform_apis: true,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
diff --git a/gnss/aidl/default/Gnss.cpp b/gnss/aidl/default/Gnss.cpp
index 7855b51..cf2c90d 100644
--- a/gnss/aidl/default/Gnss.cpp
+++ b/gnss/aidl/default/Gnss.cpp
@@ -19,6 +19,7 @@
 #include "Gnss.h"
 #include <inttypes.h>
 #include <log/log.h>
+#include <utils/Timers.h>
 #include "AGnss.h"
 #include "AGnssRil.h"
 #include "DeviceFileReader.h"
@@ -28,7 +29,6 @@
 #include "GnssConfiguration.h"
 #include "GnssDebug.h"
 #include "GnssGeofence.h"
-#include "GnssMeasurementInterface.h"
 #include "GnssNavigationMessageInterface.h"
 #include "GnssPsds.h"
 #include "GnssVisibilityControl.h"
@@ -95,6 +95,9 @@
     }
 
     mIsActive = true;
+    mThreadBlocker.reset();
+    // notify measurement engine to update measurement interval
+    mGnssMeasurementInterface->setLocationEnabled(true);
     this->reportGnssStatusValue(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
     mThread = std::thread([this]() {
         this->reportSvStatus();
@@ -102,8 +105,12 @@
             std::this_thread::sleep_for(std::chrono::milliseconds(TTFF_MILLIS));
             mFirstFixReceived = true;
         }
-        while (mIsActive == true) {
+        do {
+            if (!mIsActive) {
+                break;
+            }
             this->reportSvStatus();
+            this->reportNmea();
 
             auto currentLocation = getLocationFromHW();
             mGnssPowerIndication->notePowerConsumption();
@@ -113,12 +120,29 @@
                 const auto location = Utils::getMockLocation();
                 this->reportLocation(location);
             }
-            std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
-        }
+        } while (mIsActive && mThreadBlocker.wait_for(std::chrono::milliseconds(mMinIntervalMs)));
     });
     return ScopedAStatus::ok();
 }
 
+ScopedAStatus Gnss::stop() {
+    ALOGD("stop");
+    mIsActive = false;
+    mGnssMeasurementInterface->setLocationEnabled(false);
+    this->reportGnssStatusValue(IGnssCallback::GnssStatusValue::SESSION_END);
+    mThreadBlocker.notify();
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Gnss::close() {
+    ALOGD("close");
+    sGnssCallback = nullptr;
+    return ScopedAStatus::ok();
+}
+
 void Gnss::reportLocation(const GnssLocation& location) const {
     std::unique_lock<std::mutex> lock(mMutex);
     if (sGnssCallback == nullptr) {
@@ -153,7 +177,6 @@
 
 std::vector<GnssSvInfo> Gnss::filterBlocklistedSatellites(
         std::vector<GnssSvInfo> gnssSvInfoList) const {
-    ALOGD("filterBlocklistedSatellites");
     for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
         if (mGnssConfiguration->isBlocklisted(gnssSvInfoList[i])) {
             gnssSvInfoList[i].svFlag &= ~(uint32_t)IGnssCallback::GnssSvFlags::USED_IN_FIX;
@@ -174,14 +197,19 @@
     }
 }
 
-ScopedAStatus Gnss::stop() {
-    ALOGD("stop");
-    mIsActive = false;
-    this->reportGnssStatusValue(IGnssCallback::GnssStatusValue::SESSION_END);
-    if (mThread.joinable()) {
-        mThread.join();
+void Gnss::reportNmea() const {
+    if (mIsNmeaActive) {
+        std::unique_lock<std::mutex> lock(mMutex);
+        if (sGnssCallback == nullptr) {
+            ALOGE("%s: sGnssCallback is null.", __func__);
+            return;
+        }
+        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+        auto status = sGnssCallback->gnssNmeaCb(now, "$TEST,0,1,2,3,4,5");
+        if (!status.isOk()) {
+            ALOGE("%s: Unable to invoke callback", __func__);
+        }
     }
-    return ScopedAStatus::ok();
 }
 
 ScopedAStatus Gnss::startSvStatus() {
@@ -197,16 +225,12 @@
 }
 ScopedAStatus Gnss::startNmea() {
     ALOGD("startNmea");
+    mIsNmeaActive = true;
     return ScopedAStatus::ok();
 }
 ScopedAStatus Gnss::stopNmea() {
     ALOGD("stopNmea");
-    return ScopedAStatus::ok();
-}
-
-ScopedAStatus Gnss::close() {
-    ALOGD("close");
-    sGnssCallback = nullptr;
+    mIsNmeaActive = false;
     return ScopedAStatus::ok();
 }
 
@@ -249,7 +273,8 @@
 ScopedAStatus Gnss::setPositionMode(const PositionModeOptions& options) {
     ALOGD("setPositionMode. minIntervalMs:%d, lowPowerMode:%d", options.minIntervalMs,
           (int)options.lowPowerMode);
-    mMinIntervalMs = options.minIntervalMs;
+    mMinIntervalMs = std::max(1000, options.minIntervalMs);
+    mGnssMeasurementInterface->setLocationInterval(mMinIntervalMs);
     return ScopedAStatus::ok();
 }
 
@@ -283,8 +308,10 @@
 ScopedAStatus Gnss::getExtensionGnssMeasurement(
         std::shared_ptr<IGnssMeasurementInterface>* iGnssMeasurement) {
     ALOGD("getExtensionGnssMeasurement");
-
-    *iGnssMeasurement = SharedRefBase::make<GnssMeasurementInterface>();
+    if (mGnssMeasurementInterface == nullptr) {
+        mGnssMeasurementInterface = SharedRefBase::make<GnssMeasurementInterface>();
+    }
+    *iGnssMeasurement = mGnssMeasurementInterface;
     return ScopedAStatus::ok();
 }
 
diff --git a/gnss/aidl/default/Gnss.h b/gnss/aidl/default/Gnss.h
index 1489b4b..df10fc8 100644
--- a/gnss/aidl/default/Gnss.h
+++ b/gnss/aidl/default/Gnss.h
@@ -32,7 +32,9 @@
 #include <mutex>
 #include <thread>
 #include "GnssConfiguration.h"
+#include "GnssMeasurementInterface.h"
 #include "GnssPowerIndication.h"
+#include "Utils.h"
 
 namespace aidl::android::hardware::gnss {
 
@@ -84,6 +86,7 @@
 
     std::shared_ptr<GnssConfiguration> mGnssConfiguration;
     std::shared_ptr<GnssPowerIndication> mGnssPowerIndication;
+    std::shared_ptr<GnssMeasurementInterface> mGnssMeasurementInterface;
 
   private:
     void reportLocation(const GnssLocation&) const;
@@ -93,14 +96,17 @@
             std::vector<IGnssCallback::GnssSvInfo> gnssSvInfoList) const;
     void reportGnssStatusValue(const IGnssCallback::GnssStatusValue gnssStatusValue) const;
     std::unique_ptr<GnssLocation> getLocationFromHW();
+    void reportNmea() const;
 
     static std::shared_ptr<IGnssCallback> sGnssCallback;
 
     std::atomic<long> mMinIntervalMs;
     std::atomic<bool> mIsActive;
     std::atomic<bool> mIsSvStatusActive;
+    std::atomic<bool> mIsNmeaActive;
     std::atomic<bool> mFirstFixReceived;
     std::thread mThread;
+    ::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;
 
     mutable std::mutex mMutex;
 };
diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp
index 2c7241b..606de07 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.cpp
+++ b/gnss/aidl/default/GnssMeasurementInterface.cpp
@@ -33,10 +33,11 @@
 
 std::shared_ptr<IGnssMeasurementCallback> GnssMeasurementInterface::sCallback = nullptr;
 
-GnssMeasurementInterface::GnssMeasurementInterface() : mMinIntervalMillis(1000) {}
+GnssMeasurementInterface::GnssMeasurementInterface()
+    : mIntervalMs(1000), mLocationIntervalMs(1000), mFutures(std::vector<std::future<void>>()) {}
 
 GnssMeasurementInterface::~GnssMeasurementInterface() {
-    stop();
+    waitForStoppingThreads();
 }
 
 ndk::ScopedAStatus GnssMeasurementInterface::setCallback(
@@ -44,8 +45,10 @@
         const bool enableCorrVecOutputs) {
     ALOGD("setCallback: enableFullTracking: %d enableCorrVecOutputs: %d", (int)enableFullTracking,
           (int)enableCorrVecOutputs);
-    std::unique_lock<std::mutex> lock(mMutex);
-    sCallback = callback;
+    {
+        std::unique_lock<std::mutex> lock(mMutex);
+        sCallback = callback;
+    }
 
     if (mIsActive) {
         ALOGW("GnssMeasurement callback already set. Resetting the callback...");
@@ -60,14 +63,16 @@
         const std::shared_ptr<IGnssMeasurementCallback>& callback, const Options& options) {
     ALOGD("setCallbackWithOptions: fullTracking:%d, corrVec:%d, intervalMs:%d",
           (int)options.enableFullTracking, (int)options.enableCorrVecOutputs, options.intervalMs);
-    std::unique_lock<std::mutex> lock(mMutex);
-    sCallback = callback;
+    {
+        std::unique_lock<std::mutex> lock(mMutex);
+        sCallback = callback;
+    }
 
     if (mIsActive) {
         ALOGW("GnssMeasurement callback already set. Resetting the callback...");
         stop();
     }
-    mMinIntervalMillis = options.intervalMs;
+    mIntervalMs = std::max(options.intervalMs, 1000);
     start(options.enableCorrVecOutputs);
 
     return ndk::ScopedAStatus::ok();
@@ -75,18 +80,35 @@
 
 ndk::ScopedAStatus GnssMeasurementInterface::close() {
     ALOGD("close");
-    stop();
-    std::unique_lock<std::mutex> lock(mMutex);
-    sCallback = nullptr;
-    mMinIntervalMillis = 1000;
+    if (mIsActive) {
+        stop();
+    }
+    {
+        std::unique_lock<std::mutex> lock(mMutex);
+        sCallback = nullptr;
+    }
+    mIntervalMs = 1000;
     return ndk::ScopedAStatus::ok();
 }
 
 void GnssMeasurementInterface::start(const bool enableCorrVecOutputs) {
     ALOGD("start");
+
+    if (mIsActive) {
+        ALOGD("restarting since measurement has started");
+        stop();
+    }
+    // Wait for stopping previous thread.
+    waitForStoppingThreads();
+
     mIsActive = true;
+    mThreadBlocker.reset();
     mThread = std::thread([this, enableCorrVecOutputs]() {
-        while (mIsActive == true) {
+        int intervalMs;
+        do {
+            if (!mIsActive) {
+                break;
+            }
             std::string rawMeasurementStr = "";
             if (ReplayUtils::hasGnssDeviceFile() &&
                 ReplayUtils::isGnssRawMeasurement(
@@ -103,15 +125,19 @@
                 auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs);
                 this->reportMeasurement(measurement);
             }
-            std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
-        }
+            intervalMs =
+                    (mLocationEnabled) ? std::min(mLocationIntervalMs, mIntervalMs) : mIntervalMs;
+        } while (mIsActive && mThreadBlocker.wait_for(std::chrono::milliseconds(intervalMs)));
     });
-    mThread.detach();
 }
 
 void GnssMeasurementInterface::stop() {
     ALOGD("stop");
     mIsActive = false;
+    mThreadBlocker.notify();
+    if (mThread.joinable()) {
+        mFutures.push_back(std::async(std::launch::async, [this] { mThread.join(); }));
+    }
 }
 
 void GnssMeasurementInterface::reportMeasurement(const GnssData& data) {
@@ -128,4 +154,21 @@
     callbackCopy->gnssMeasurementCb(data);
 }
 
+void GnssMeasurementInterface::setLocationInterval(const int intervalMs) {
+    mLocationIntervalMs = intervalMs;
+}
+
+void GnssMeasurementInterface::setLocationEnabled(const bool enabled) {
+    mLocationEnabled = enabled;
+}
+
+void GnssMeasurementInterface::waitForStoppingThreads() {
+    for (auto& future : mFutures) {
+        ALOGD("Stopping previous thread.");
+        future.wait();
+        ALOGD("Done stopping thread.");
+    }
+    mFutures.clear();
+}
+
 }  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssMeasurementInterface.h b/gnss/aidl/default/GnssMeasurementInterface.h
index bf77806..bb08027 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.h
+++ b/gnss/aidl/default/GnssMeasurementInterface.h
@@ -19,8 +19,10 @@
 #include <aidl/android/hardware/gnss/BnGnssMeasurementCallback.h>
 #include <aidl/android/hardware/gnss/BnGnssMeasurementInterface.h>
 #include <atomic>
+#include <future>
 #include <mutex>
 #include <thread>
+#include "Utils.h"
 
 namespace aidl::android::hardware::gnss {
 
@@ -35,15 +37,22 @@
     ndk::ScopedAStatus setCallbackWithOptions(
             const std::shared_ptr<IGnssMeasurementCallback>& callback,
             const Options& options) override;
+    void setLocationInterval(const int intervalMs);
+    void setLocationEnabled(const bool enabled);
 
   private:
     void start(const bool enableCorrVecOutputs);
     void stop();
     void reportMeasurement(const GnssData&);
+    void waitForStoppingThreads();
 
-    std::atomic<long> mMinIntervalMillis;
+    std::atomic<long> mIntervalMs;
+    std::atomic<long> mLocationIntervalMs;
     std::atomic<bool> mIsActive;
+    std::atomic<bool> mLocationEnabled;
     std::thread mThread;
+    std::vector<std::future<void>> mFutures;
+    ::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;
 
     // Guarded by mMutex
     static std::shared_ptr<IGnssMeasurementCallback> sCallback;
diff --git a/gnss/aidl/default/GnssNavigationMessageInterface.cpp b/gnss/aidl/default/GnssNavigationMessageInterface.cpp
index 4bc859d..75b9624 100644
--- a/gnss/aidl/default/GnssNavigationMessageInterface.cpp
+++ b/gnss/aidl/default/GnssNavigationMessageInterface.cpp
@@ -32,7 +32,7 @@
 GnssNavigationMessageInterface::GnssNavigationMessageInterface() : mMinIntervalMillis(1000) {}
 
 GnssNavigationMessageInterface::~GnssNavigationMessageInterface() {
-    stop();
+    waitForStoppingThreads();
 }
 
 ndk::ScopedAStatus GnssNavigationMessageInterface::setCallback(
@@ -46,7 +46,9 @@
 
 ndk::ScopedAStatus GnssNavigationMessageInterface::close() {
     ALOGD("close");
-    stop();
+    if (mIsActive) {
+        stop();
+    }
     std::unique_lock<std::mutex> lock(mMutex);
     sCallback = nullptr;
     return ndk::ScopedAStatus::ok();
@@ -54,9 +56,20 @@
 
 void GnssNavigationMessageInterface::start() {
     ALOGD("start");
+
+    if (mIsActive) {
+        ALOGD("restarting since nav msg has started");
+        stop();
+    }
+    // Wait for stopping previous thread.
+    waitForStoppingThreads();
+
     mIsActive = true;
     mThread = std::thread([this]() {
-        while (mIsActive == true) {
+        do {
+            if (!mIsActive) {
+                break;
+            }
             GnssNavigationMessage message = {
                     .svid = 19,
                     .type = GnssNavigationMessageType::GPS_L1CA,
@@ -66,15 +79,18 @@
                     .data = std::vector<uint8_t>(40, 0xF9),
             };
             this->reportMessage(message);
-            std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
-        }
+        } while (mIsActive &&
+                 mThreadBlocker.wait_for(std::chrono::milliseconds(mMinIntervalMillis)));
     });
-    mThread.detach();
 }
 
 void GnssNavigationMessageInterface::stop() {
     ALOGD("stop");
     mIsActive = false;
+    mThreadBlocker.notify();
+    if (mThread.joinable()) {
+        mFutures.push_back(std::async(std::launch::async, [this] { mThread.join(); }));
+    }
 }
 
 void GnssNavigationMessageInterface::reportMessage(const GnssNavigationMessage& message) {
@@ -91,4 +107,13 @@
     callbackCopy->gnssNavigationMessageCb(message);
 }
 
+void GnssNavigationMessageInterface::waitForStoppingThreads() {
+    for (auto& future : mFutures) {
+        ALOGD("Stopping previous thread.");
+        future.wait();
+        ALOGD("Done stopping thread.");
+    }
+    mFutures.clear();
+}
+
 }  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssNavigationMessageInterface.h b/gnss/aidl/default/GnssNavigationMessageInterface.h
index 600b23a..b335348 100644
--- a/gnss/aidl/default/GnssNavigationMessageInterface.h
+++ b/gnss/aidl/default/GnssNavigationMessageInterface.h
@@ -18,7 +18,9 @@
 
 #include <aidl/android/hardware/gnss/BnGnssNavigationMessageInterface.h>
 #include <atomic>
+#include <future>
 #include <thread>
+#include "Utils.h"
 
 namespace aidl::android::hardware::gnss {
 
@@ -34,10 +36,13 @@
     void start();
     void stop();
     void reportMessage(const IGnssNavigationMessageCallback::GnssNavigationMessage& message);
+    void waitForStoppingThreads();
 
     std::atomic<long> mMinIntervalMillis;
     std::atomic<bool> mIsActive;
     std::thread mThread;
+    std::vector<std::future<void>> mFutures;
+    ::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;
 
     // Guarded by mMutex
     static std::shared_ptr<IGnssNavigationMessageCallback> sCallback;
diff --git a/gnss/aidl/vts/GnssCallbackAidl.cpp b/gnss/aidl/vts/GnssCallbackAidl.cpp
index 77a2506..2f6128b 100644
--- a/gnss/aidl/vts/GnssCallbackAidl.cpp
+++ b/gnss/aidl/vts/GnssCallbackAidl.cpp
@@ -31,7 +31,7 @@
 }
 
 Status GnssCallbackAidl::gnssStatusCb(const GnssStatusValue /* status */) {
-    ALOGI("gnssSvStatusCb");
+    ALOGI("gnssStatusCb");
     return Status::ok();
 }
 
@@ -47,7 +47,8 @@
     return Status::ok();
 }
 
-Status GnssCallbackAidl::gnssNmeaCb(const int64_t /* timestamp */, const std::string& /* nmea */) {
+Status GnssCallbackAidl::gnssNmeaCb(const int64_t timestamp, const std::string& nmea) {
+    nmea_cbq_.store(std::make_pair(timestamp, nmea));
     return Status::ok();
 }
 
diff --git a/gnss/aidl/vts/GnssCallbackAidl.h b/gnss/aidl/vts/GnssCallbackAidl.h
index 209728d..a9495ba 100644
--- a/gnss/aidl/vts/GnssCallbackAidl.h
+++ b/gnss/aidl/vts/GnssCallbackAidl.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <android/hardware/gnss/BnGnssCallback.h>
+#include <utility>
 #include "GnssCallbackEventQueue.h"
 
 /* Callback class for data & Event. */
@@ -26,7 +27,8 @@
         : capabilities_cbq_("capabilities"),
           info_cbq_("system_info"),
           location_cbq_("location"),
-          sv_info_list_cbq_("sv_info"){};
+          sv_info_list_cbq_("sv_info"),
+          nmea_cbq_("nmea"){};
     ~GnssCallbackAidl(){};
 
     android::binder::Status gnssSetCapabilitiesCb(const int capabilities) override;
@@ -55,4 +57,6 @@
     android::hardware::gnss::common::GnssCallbackEventQueue<
             std::vector<android::hardware::gnss::IGnssCallback::GnssSvInfo>>
             sv_info_list_cbq_;
+    android::hardware::gnss::common::GnssCallbackEventQueue<std::pair<int64_t, std::string>>
+            nmea_cbq_;
 };
\ No newline at end of file
diff --git a/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp b/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp
index c4fad7f..a553954 100644
--- a/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp
+++ b/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp
@@ -24,12 +24,10 @@
 
 android::binder::Status GnssMeasurementCallbackAidl::gnssMeasurementCb(const GnssData& gnssData) {
     ALOGI("gnssMeasurementCb");
-    ALOGI("elapsedRealtime: flags = %d, timestampNs: %" PRId64 ", timeUncertaintyNs=%lf",
+    ALOGV("elapsedRealtime: flags = 0x%X, timestampNs: %" PRId64 ", timeUncertaintyNs=%lf",
           gnssData.elapsedRealtime.flags, gnssData.elapsedRealtime.timestampNs,
           gnssData.elapsedRealtime.timeUncertaintyNs);
-    for (const auto& measurement : gnssData.measurements) {
-        ALOGI("measurement.receivedSvTimeInNs=%" PRId64, measurement.receivedSvTimeInNs);
-    }
+
     gnss_data_cbq_.store(gnssData);
     return android::binder::Status::ok();
 }
diff --git a/gnss/aidl/vts/gnss_hal_test.cpp b/gnss/aidl/vts/gnss_hal_test.cpp
index f184f81..0e1218e 100644
--- a/gnss/aidl/vts/gnss_hal_test.cpp
+++ b/gnss/aidl/vts/gnss_hal_test.cpp
@@ -18,15 +18,50 @@
 
 #include "gnss_hal_test.h"
 #include <hidl/ServiceManagement.h>
+#include <algorithm>
+#include <cmath>
 #include "Utils.h"
 
+using android::hardware::gnss::GnssClock;
 using android::hardware::gnss::GnssConstellationType;
+using android::hardware::gnss::GnssData;
 using android::hardware::gnss::GnssLocation;
+using android::hardware::gnss::GnssMeasurement;
 using android::hardware::gnss::IGnss;
 using android::hardware::gnss::IGnssCallback;
+using android::hardware::gnss::IGnssMeasurementInterface;
 using android::hardware::gnss::common::Utils;
 using GnssConstellationTypeV2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
 
+namespace {
+// The difference between the mean of the received intervals and the requested interval should not
+// be larger mInterval * ALLOWED_MEAN_ERROR_RATIO
+constexpr double ALLOWED_MEAN_ERROR_RATIO = 0.25;
+
+// The standard deviation computed for the deltas should not be bigger
+// than mInterval * ALLOWED_STDEV_ERROR_RATIO or MIN_STDEV_MS, whichever is higher.
+constexpr double ALLOWED_STDEV_ERROR_RATIO = 0.50;
+constexpr double MIN_STDEV_MS = 1000;
+
+double computeMean(std::vector<int>& deltas) {
+    long accumulator = 0;
+    for (auto& d : deltas) {
+        accumulator += d;
+    }
+    return accumulator / deltas.size();
+}
+
+double computeStdev(double mean, std::vector<int>& deltas) {
+    double accumulator = 0;
+    for (auto& d : deltas) {
+        double diff = d - mean;
+        accumulator += diff * diff;
+    }
+    return std::sqrt(accumulator / (deltas.size() - 1));
+}
+
+}  // anonymous namespace
+
 void GnssHalTest::SetUp() {
     // Get AIDL handle
     aidl_gnss_hal_ = android::waitForDeclaredService<IGnssAidl>(String16(GetParam().c_str()));
@@ -97,19 +132,25 @@
     ASSERT_TRUE(status.isOk());
 }
 
-bool GnssHalTest::StartAndCheckFirstLocation(const int min_interval_msec,
-                                             const bool low_power_mode) {
+bool GnssHalTest::StartAndCheckFirstLocation(const int min_interval_msec, const bool low_power_mode,
+                                             const bool start_sv_status, const bool start_nmea) {
     if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
         // Invoke the super method.
         return GnssHalTestTemplate<IGnss_V2_1>::StartAndCheckFirstLocation(min_interval_msec,
                                                                            low_power_mode);
     }
-
     SetPositionMode(min_interval_msec, low_power_mode);
-    auto status = aidl_gnss_hal_->start();
-    EXPECT_TRUE(status.isOk());
 
-    status = aidl_gnss_hal_->startSvStatus();
+    if (start_sv_status) {
+        auto status = aidl_gnss_hal_->startSvStatus();
+        EXPECT_TRUE(status.isOk());
+    }
+    if (start_nmea) {
+        auto status = aidl_gnss_hal_->startNmea();
+        EXPECT_TRUE(status.isOk());
+    }
+
+    auto status = aidl_gnss_hal_->start();
     EXPECT_TRUE(status.isOk());
 
     /*
@@ -131,6 +172,12 @@
     return false;
 }
 
+bool GnssHalTest::StartAndCheckFirstLocation(const int min_interval_msec,
+                                             const bool low_power_mode) {
+    return StartAndCheckFirstLocation(min_interval_msec, low_power_mode,
+                                      /* start_sv_status= */ true, /* start_nmea= */ true);
+}
+
 void GnssHalTest::StopAndClearLocations() {
     ALOGD("StopAndClearLocations");
     if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
@@ -139,6 +186,8 @@
     }
     auto status = aidl_gnss_hal_->stopSvStatus();
     EXPECT_TRUE(status.isOk());
+    status = aidl_gnss_hal_->stopNmea();
+    EXPECT_TRUE(status.isOk());
 
     status = aidl_gnss_hal_->stop();
     EXPECT_TRUE(status.isOk());
@@ -153,7 +202,8 @@
     aidl_gnss_cb_->location_cbq_.reset();
 }
 
-void GnssHalTest::StartAndCheckLocations(int count) {
+void GnssHalTest::StartAndCheckLocations(const int count, const bool start_sv_status,
+                                         const bool start_nmea) {
     if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
         // Invoke the super method.
         return GnssHalTestTemplate<IGnss_V2_1>::StartAndCheckLocations(count);
@@ -162,7 +212,8 @@
     const int kLocationTimeoutSubsequentSec = 2;
     const bool kLowPowerMode = false;
 
-    EXPECT_TRUE(StartAndCheckFirstLocation(kMinIntervalMsec, kLowPowerMode));
+    EXPECT_TRUE(StartAndCheckFirstLocation(kMinIntervalMsec, kLowPowerMode, start_sv_status,
+                                           start_nmea));
 
     for (int i = 1; i < count; i++) {
         EXPECT_TRUE(aidl_gnss_cb_->location_cbq_.retrieve(aidl_gnss_cb_->last_location_,
@@ -177,6 +228,10 @@
     }
 }
 
+void GnssHalTest::StartAndCheckLocations(const int count) {
+    StartAndCheckLocations(count, /* start_sv_status= */ true, /* start_nmea= */ true);
+}
+
 std::list<std::vector<IGnssCallback::GnssSvInfo>> GnssHalTest::convertToAidl(
         const std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>>& sv_info_list) {
     std::list<std::vector<IGnssCallback::GnssSvInfo>> aidl_sv_info_list;
@@ -313,3 +368,109 @@
 
     return constellation_to_blocklist;
 }
+
+void GnssHalTest::checkGnssMeasurementClockFields(const GnssData& measurement) {
+    Utils::checkElapsedRealtime(measurement.elapsedRealtime);
+    ASSERT_TRUE(measurement.clock.gnssClockFlags >= 0 &&
+                measurement.clock.gnssClockFlags <=
+                        (GnssClock::HAS_LEAP_SECOND | GnssClock::HAS_TIME_UNCERTAINTY |
+                         GnssClock::HAS_FULL_BIAS | GnssClock::HAS_BIAS |
+                         GnssClock::HAS_BIAS_UNCERTAINTY | GnssClock::HAS_DRIFT |
+                         GnssClock::HAS_DRIFT_UNCERTAINTY));
+}
+
+void GnssHalTest::checkGnssMeasurementFlags(const GnssMeasurement& measurement) {
+    ASSERT_TRUE(measurement.flags >= 0 &&
+                measurement.flags <=
+                        (GnssMeasurement::HAS_SNR | GnssMeasurement::HAS_CARRIER_FREQUENCY |
+                         GnssMeasurement::HAS_CARRIER_CYCLES | GnssMeasurement::HAS_CARRIER_PHASE |
+                         GnssMeasurement::HAS_CARRIER_PHASE_UNCERTAINTY |
+                         GnssMeasurement::HAS_AUTOMATIC_GAIN_CONTROL |
+                         GnssMeasurement::HAS_FULL_ISB | GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY |
+                         GnssMeasurement::HAS_SATELLITE_ISB |
+                         GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY |
+                         GnssMeasurement::HAS_SATELLITE_PVT |
+                         GnssMeasurement::HAS_CORRELATION_VECTOR));
+}
+
+void GnssHalTest::checkGnssMeasurementFields(const GnssMeasurement& measurement,
+                                             const GnssData& data) {
+    checkGnssMeasurementFlags(measurement);
+    // Verify CodeType is valid.
+    ASSERT_NE(measurement.signalType.codeType, "");
+    // Verify basebandCn0DbHz is valid.
+    ASSERT_TRUE(measurement.basebandCN0DbHz > 0.0 && measurement.basebandCN0DbHz <= 65.0);
+
+    if (((measurement.flags & GnssMeasurement::HAS_FULL_ISB) > 0) &&
+        ((measurement.flags & GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY) > 0) &&
+        ((measurement.flags & GnssMeasurement::HAS_SATELLITE_ISB) > 0) &&
+        ((measurement.flags & GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY) > 0)) {
+        GnssConstellationType referenceConstellation =
+                data.clock.referenceSignalTypeForIsb.constellation;
+        double carrierFrequencyHz = data.clock.referenceSignalTypeForIsb.carrierFrequencyHz;
+        std::string codeType = data.clock.referenceSignalTypeForIsb.codeType;
+
+        ASSERT_TRUE(referenceConstellation >= GnssConstellationType::UNKNOWN &&
+                    referenceConstellation <= GnssConstellationType::IRNSS);
+        ASSERT_TRUE(carrierFrequencyHz > 0);
+        ASSERT_NE(codeType, "");
+
+        ASSERT_TRUE(std::abs(measurement.fullInterSignalBiasNs) < 1.0e6);
+        ASSERT_TRUE(measurement.fullInterSignalBiasUncertaintyNs >= 0);
+        ASSERT_TRUE(std::abs(measurement.satelliteInterSignalBiasNs) < 1.0e6);
+        ASSERT_TRUE(measurement.satelliteInterSignalBiasUncertaintyNs >= 0);
+    }
+}
+
+void GnssHalTest::startMeasurementWithInterval(
+        int intervalMs, const sp<IGnssMeasurementInterface>& iGnssMeasurement,
+        sp<GnssMeasurementCallbackAidl>& callback) {
+    ALOGD("Start requesting measurement at interval of %d millis.", intervalMs);
+    IGnssMeasurementInterface::Options options;
+    options.intervalMs = intervalMs;
+    auto status = iGnssMeasurement->setCallbackWithOptions(callback, options);
+    ASSERT_TRUE(status.isOk());
+}
+
+void GnssHalTest::collectMeasurementIntervals(const sp<GnssMeasurementCallbackAidl>& callback,
+                                              const int numMeasurementEvents,
+                                              const int timeoutSeconds,
+                                              std::vector<int>& deltasMs) {
+    int64_t lastElapsedRealtimeMillis = 0;
+    for (int i = 0; i < numMeasurementEvents; i++) {
+        GnssData lastGnssData;
+        ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastGnssData, timeoutSeconds));
+        EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
+        ASSERT_TRUE(lastGnssData.measurements.size() > 0);
+
+        // Validity check GnssData fields
+        checkGnssMeasurementClockFields(lastGnssData);
+        for (const auto& measurement : lastGnssData.measurements) {
+            checkGnssMeasurementFields(measurement, lastGnssData);
+        }
+
+        long currentElapsedRealtimeMillis = lastGnssData.elapsedRealtime.timestampNs * 1e-6;
+        if (lastElapsedRealtimeMillis != 0) {
+            deltasMs.push_back(currentElapsedRealtimeMillis - lastElapsedRealtimeMillis);
+        }
+        lastElapsedRealtimeMillis = currentElapsedRealtimeMillis;
+    }
+}
+
+void GnssHalTest::assertMeanAndStdev(int intervalMs, std::vector<int>& deltasMs) {
+    double mean = computeMean(deltasMs);
+    double stdev = computeStdev(mean, deltasMs);
+    EXPECT_TRUE(std::abs(mean - intervalMs) <= intervalMs * ALLOWED_MEAN_ERROR_RATIO)
+            << "Test failed, because the mean of intervals is " << mean
+            << " millis. The test requires that abs(" << mean << " - " << intervalMs
+            << ") <= " << intervalMs * ALLOWED_MEAN_ERROR_RATIO
+            << " millis, when the requested interval is " << intervalMs << " millis.";
+
+    double maxStdev = std::max(MIN_STDEV_MS, intervalMs * ALLOWED_STDEV_ERROR_RATIO);
+    EXPECT_TRUE(stdev <= maxStdev)
+            << "Test failed, because the stdev of intervals is " << stdev
+            << " millis, which must be <= " << maxStdev
+            << " millis, when the requested interval is " << intervalMs << " millis.";
+    ALOGD("Mean of interval deltas in millis: %.1lf", mean);
+    ALOGD("Stdev of interval deltas in millis: %.1lf", stdev);
+}
diff --git a/gnss/aidl/vts/gnss_hal_test.h b/gnss/aidl/vts/gnss_hal_test.h
index d479af3..645fc82 100644
--- a/gnss/aidl/vts/gnss_hal_test.h
+++ b/gnss/aidl/vts/gnss_hal_test.h
@@ -25,6 +25,7 @@
 #include <android/hardware/gnss/2.1/IGnss.h>
 #include "GnssBatchingCallback.h"
 #include "GnssCallbackAidl.h"
+#include "GnssMeasurementCallbackAidl.h"
 #include "v2_1/gnss_hal_test_template.h"
 
 using IGnss_V2_1 = android::hardware::gnss::V2_1::IGnss;
@@ -68,8 +69,11 @@
                        const bool check_speed);
     void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
     bool StartAndCheckFirstLocation(const int min_interval_msec, const bool low_power_mode);
+    bool StartAndCheckFirstLocation(const int min_interval_msec, const bool low_power_mode,
+                                    const bool start_sv_status, const bool start_nmea);
     void StopAndClearLocations();
-    void StartAndCheckLocations(int count);
+    void StartAndCheckLocations(const int count);
+    void StartAndCheckLocations(const int count, const bool start_sv_status, const bool start_nmea);
 
     android::hardware::gnss::GnssConstellationType startLocationAndGetNonGpsConstellation(
             const int locations_to_await, const int gnss_sv_info_list_timeout);
@@ -85,6 +89,19 @@
                     sv_info_list,
             const int min_observations);
 
+    void checkGnssMeasurementClockFields(const android::hardware::gnss::GnssData& measurement);
+    void checkGnssMeasurementFlags(const android::hardware::gnss::GnssMeasurement& measurement);
+    void checkGnssMeasurementFields(const android::hardware::gnss::GnssMeasurement& measurement,
+                                    const android::hardware::gnss::GnssData& data);
+    void startMeasurementWithInterval(
+            int intervalMillis,
+            const sp<android::hardware::gnss::IGnssMeasurementInterface>& iMeasurement,
+            sp<GnssMeasurementCallbackAidl>& callback);
+    void collectMeasurementIntervals(const sp<GnssMeasurementCallbackAidl>& callback,
+                                     const int numMeasurementEvents, const int timeoutSeconds,
+                                     std::vector<int>& deltaMs);
+    void assertMeanAndStdev(int intervalMillis, std::vector<int>& deltasMillis);
+
     sp<IGnssAidl> aidl_gnss_hal_;
     sp<GnssCallbackAidl> aidl_gnss_cb_;  // Primary callback interface
 };
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
index 54946fb..3696233 100644
--- a/gnss/aidl/vts/gnss_hal_test_cases.cpp
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -28,7 +28,9 @@
 #include <android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.h>
 #include <android/hardware/gnss/visibility_control/IGnssVisibilityControl.h>
 #include <cutils/properties.h>
+#include <utils/SystemClock.h>
 #include <cmath>
+#include <utility>
 #include "AGnssCallbackAidl.h"
 #include "AGnssRilCallbackAidl.h"
 #include "GnssAntennaInfoCallbackAidl.h"
@@ -289,10 +291,12 @@
         EXPECT_GT(aidl_gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_lists, kNumSvInfoLists,
                                                             kTimeoutSeconds),
                   0);
-        last_sv_info_list = sv_info_lists.back();
-    } while (last_sv_info_list.size() == 0);
+        if (!sv_info_lists.empty()) {
+            last_sv_info_list = sv_info_lists.back();
+            ALOGD("last_sv_info size = %d", (int)last_sv_info_list.size());
+        }
+    } while (!sv_info_lists.empty() && last_sv_info_list.size() == 0);
 
-    ALOGD("last_sv_info size = %d", (int)last_sv_info_list.size());
     bool nonZeroCn0Found = false;
     for (auto sv_info : last_sv_info_list) {
         EXPECT_TRUE(sv_info.basebandCN0DbHz >= 0.0 && sv_info.basebandCN0DbHz <= 65.0);
@@ -376,58 +380,6 @@
     }
 }
 
-void CheckGnssMeasurementClockFields(const GnssData& measurement) {
-    Utils::checkElapsedRealtime(measurement.elapsedRealtime);
-    ASSERT_TRUE(measurement.clock.gnssClockFlags >= 0 &&
-                measurement.clock.gnssClockFlags <=
-                        (GnssClock::HAS_LEAP_SECOND | GnssClock::HAS_TIME_UNCERTAINTY |
-                         GnssClock::HAS_FULL_BIAS | GnssClock::HAS_BIAS |
-                         GnssClock::HAS_BIAS_UNCERTAINTY | GnssClock::HAS_DRIFT |
-                         GnssClock::HAS_DRIFT_UNCERTAINTY));
-}
-
-void CheckGnssMeasurementFlags(const GnssMeasurement& measurement) {
-    ASSERT_TRUE(measurement.flags >= 0 &&
-                measurement.flags <=
-                        (GnssMeasurement::HAS_SNR | GnssMeasurement::HAS_CARRIER_FREQUENCY |
-                         GnssMeasurement::HAS_CARRIER_CYCLES | GnssMeasurement::HAS_CARRIER_PHASE |
-                         GnssMeasurement::HAS_CARRIER_PHASE_UNCERTAINTY |
-                         GnssMeasurement::HAS_AUTOMATIC_GAIN_CONTROL |
-                         GnssMeasurement::HAS_FULL_ISB | GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY |
-                         GnssMeasurement::HAS_SATELLITE_ISB |
-                         GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY |
-                         GnssMeasurement::HAS_SATELLITE_PVT |
-                         GnssMeasurement::HAS_CORRELATION_VECTOR));
-}
-
-void CheckGnssMeasurementFields(const GnssMeasurement& measurement, const GnssData& data) {
-    CheckGnssMeasurementFlags(measurement);
-    // Verify CodeType is valid.
-    ASSERT_NE(measurement.signalType.codeType, "");
-    // Verify basebandCn0DbHz is valid.
-    ASSERT_TRUE(measurement.basebandCN0DbHz > 0.0 && measurement.basebandCN0DbHz <= 65.0);
-
-    if (((measurement.flags & GnssMeasurement::HAS_FULL_ISB) > 0) &&
-        ((measurement.flags & GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY) > 0) &&
-        ((measurement.flags & GnssMeasurement::HAS_SATELLITE_ISB) > 0) &&
-        ((measurement.flags & GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY) > 0)) {
-        GnssConstellationType referenceConstellation =
-                data.clock.referenceSignalTypeForIsb.constellation;
-        double carrierFrequencyHz = data.clock.referenceSignalTypeForIsb.carrierFrequencyHz;
-        std::string codeType = data.clock.referenceSignalTypeForIsb.codeType;
-
-        ASSERT_TRUE(referenceConstellation >= GnssConstellationType::UNKNOWN &&
-                    referenceConstellation <= GnssConstellationType::IRNSS);
-        ASSERT_TRUE(carrierFrequencyHz > 0);
-        ASSERT_NE(codeType, "");
-
-        ASSERT_TRUE(std::abs(measurement.fullInterSignalBiasNs) < 1.0e6);
-        ASSERT_TRUE(measurement.fullInterSignalBiasUncertaintyNs >= 0);
-        ASSERT_TRUE(std::abs(measurement.satelliteInterSignalBiasNs) < 1.0e6);
-        ASSERT_TRUE(measurement.satelliteInterSignalBiasUncertaintyNs >= 0);
-    }
-}
-
 /*
  * TestGnssMeasurementExtensionAndSatellitePvt:
  * 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
@@ -465,10 +417,10 @@
         ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
 
         // Validity check GnssData fields
-        CheckGnssMeasurementClockFields(lastMeasurement);
+        checkGnssMeasurementClockFields(lastMeasurement);
 
         for (const auto& measurement : lastMeasurement.measurements) {
-            CheckGnssMeasurementFields(measurement, lastMeasurement);
+            checkGnssMeasurementFields(measurement, lastMeasurement);
             if (measurement.flags & GnssMeasurement::HAS_SATELLITE_PVT &&
                 kIsSatellitePvtSupported == true) {
                 ALOGD("Found a measurement with SatellitePvt");
@@ -525,10 +477,10 @@
         ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
 
         // Validity check GnssData fields
-        CheckGnssMeasurementClockFields(lastMeasurement);
+        checkGnssMeasurementClockFields(lastMeasurement);
 
         for (const auto& measurement : lastMeasurement.measurements) {
-            CheckGnssMeasurementFields(measurement, lastMeasurement);
+            checkGnssMeasurementFields(measurement, lastMeasurement);
             if (measurement.flags & GnssMeasurement::HAS_CORRELATION_VECTOR) {
                 correlationVectorFound = true;
                 ASSERT_TRUE(measurement.correlationVectors.size() > 0);
@@ -1242,48 +1194,6 @@
 }
 
 /*
- * TestGnssMeasurementSetCallbackWithOptions:
- * 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
- * 2. Sets a GnssMeasurementCallback with intervalMillis option, waits for measurements reported,
- *    and verifies mandatory fields are valid.
- */
-TEST_P(GnssHalTest, TestGnssMeasurementSetCallbackWithOptions) {
-    if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
-        return;
-    }
-    const int kFirstGnssMeasurementTimeoutSeconds = 10;
-    const int kNumMeasurementEvents = 5;
-
-    sp<IGnssMeasurementInterface> iGnssMeasurement;
-    auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
-    ASSERT_TRUE(status.isOk());
-    ASSERT_TRUE(iGnssMeasurement != nullptr);
-
-    auto callback = sp<GnssMeasurementCallbackAidl>::make();
-    IGnssMeasurementInterface::Options options;
-    options.intervalMs = 2000;
-    status = iGnssMeasurement->setCallbackWithOptions(callback, options);
-    ASSERT_TRUE(status.isOk());
-
-    for (int i = 0; i < kNumMeasurementEvents; i++) {
-        GnssData lastMeasurement;
-        ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastMeasurement,
-                                                      kFirstGnssMeasurementTimeoutSeconds));
-        EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
-        ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
-
-        // Validity check GnssData fields
-        CheckGnssMeasurementClockFields(lastMeasurement);
-        for (const auto& measurement : lastMeasurement.measurements) {
-            CheckGnssMeasurementFields(measurement, lastMeasurement);
-        }
-    }
-
-    status = iGnssMeasurement->close();
-    ASSERT_TRUE(status.isOk());
-}
-
-/*
  * TestGnssAgcInGnssMeasurement:
  * 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
  * 2. Sets a GnssMeasurementCallback, waits for a measurement.
@@ -1293,7 +1203,7 @@
         return;
     }
     const int kFirstGnssMeasurementTimeoutSeconds = 10;
-    const int kNumMeasurementEvents = 15;
+    const int kNumMeasurementEvents = 5;
 
     sp<IGnssMeasurementInterface> iGnssMeasurement;
     auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
@@ -1313,7 +1223,7 @@
         ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
 
         // Validity check GnssData fields
-        CheckGnssMeasurementClockFields(lastMeasurement);
+        checkGnssMeasurementClockFields(lastMeasurement);
 
         ASSERT_TRUE(lastMeasurement.gnssAgcs.size() > 0);
         for (const auto& gnssAgc : lastMeasurement.gnssAgcs) {
@@ -1444,3 +1354,143 @@
             Utils::getMockMeasurementCorrections_aidl());
     ASSERT_TRUE(status.isOk());
 }
+
+/*
+ * TestStopSvStatusAndNmea:
+ * 1. Call stopSvStatus and stopNmea.
+ * 2. Start location and verify that
+ *    - no SvStatus is received.
+ *    - no Nmea is received.
+ */
+TEST_P(GnssHalTest, TestStopSvStatusAndNmea) {
+    if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
+        return;
+    }
+    auto status = aidl_gnss_hal_->stopSvStatus();
+    EXPECT_TRUE(status.isOk());
+    status = aidl_gnss_hal_->stopNmea();
+    EXPECT_TRUE(status.isOk());
+
+    int kLocationsToAwait = 5;
+    aidl_gnss_cb_->location_cbq_.reset();
+    aidl_gnss_cb_->sv_info_list_cbq_.reset();
+    aidl_gnss_cb_->nmea_cbq_.reset();
+    StartAndCheckLocations(/* count= */ kLocationsToAwait,
+                           /* start_sv_status= */ false, /* start_nmea= */ false);
+    int location_called_count = aidl_gnss_cb_->location_cbq_.calledCount();
+    ALOGD("Observed %d GnssSvStatus, and %d Nmea while awaiting %d locations (%d received)",
+          aidl_gnss_cb_->sv_info_list_cbq_.size(), aidl_gnss_cb_->nmea_cbq_.size(),
+          kLocationsToAwait, location_called_count);
+
+    // Ensure that no SvStatus & no Nmea is received.
+    EXPECT_EQ(aidl_gnss_cb_->sv_info_list_cbq_.size(), 0);
+    EXPECT_EQ(aidl_gnss_cb_->nmea_cbq_.size(), 0);
+
+    StopAndClearLocations();
+}
+
+/*
+ * TestGnssMeasurementIntervals_WithoutLocation:
+ * 1. start measurement with interval
+ * 2. verify that the received measurement intervals have expected mean and stdev
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementIntervals_WithoutLocation) {
+    if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
+        return;
+    }
+
+    std::vector<int> intervals({2000, 4000});
+    std::vector<int> numEvents({10, 5});
+
+    sp<IGnssMeasurementInterface> iGnssMeasurement;
+    auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+    ALOGD("TestGnssMeasurementIntervals_WithoutLocation");
+    for (int i = 0; i < intervals.size(); i++) {
+        auto callback = sp<GnssMeasurementCallbackAidl>::make();
+        startMeasurementWithInterval(intervals[i], iGnssMeasurement, callback);
+
+        std::vector<int> deltas;
+        collectMeasurementIntervals(callback, numEvents[i], /* timeoutSeconds= */ 10, deltas);
+
+        status = iGnssMeasurement->close();
+        ASSERT_TRUE(status.isOk());
+
+        assertMeanAndStdev(intervals[i], deltas);
+    }
+}
+
+/*
+ * TestGnssMeasurementIntervals_LocationOnBeforeMeasurement:
+ * 1. start measurement with interval
+ * 2. verify that the received measurement intervals have expected mean and stdev
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementIntervals_LocationOnBeforeMeasurement) {
+    if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
+        return;
+    }
+
+    std::vector<int> intervals({2000});
+
+    sp<IGnssMeasurementInterface> iGnssMeasurement;
+    auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+    int locationIntervalMs = 1000;
+
+    // Start location first and then start measurement
+    ALOGD("TestGnssMeasurementIntervals_LocationOnBeforeMeasurement");
+    StartAndCheckFirstLocation(locationIntervalMs, /* lowPowerMode= */ false);
+    for (auto& intervalMs : intervals) {
+        auto callback = sp<GnssMeasurementCallbackAidl>::make();
+        startMeasurementWithInterval(intervalMs, iGnssMeasurement, callback);
+
+        std::vector<int> deltas;
+        collectMeasurementIntervals(callback, /*numEvents=*/10, /*timeoutSeconds=*/10, deltas);
+
+        status = iGnssMeasurement->close();
+        ASSERT_TRUE(status.isOk());
+
+        assertMeanAndStdev(locationIntervalMs, deltas);
+    }
+    StopAndClearLocations();
+}
+
+/*
+ * TestGnssMeasurementIntervals:
+ * 1. start measurement with interval
+ * 2. verify that the received measurement intervals have expected mean and stdev
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementIntervals_LocationOnAfterMeasurement) {
+    if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
+        return;
+    }
+
+    std::vector<int> intervals({2000});
+
+    sp<IGnssMeasurementInterface> iGnssMeasurement;
+    auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+    int locationIntervalMs = 1000;
+    // Start location first and then start measurement
+    ALOGD("TestGnssMeasurementIntervals_LocationOnAfterMeasurement");
+    for (auto& intervalMs : intervals) {
+        auto callback = sp<GnssMeasurementCallbackAidl>::make();
+        startMeasurementWithInterval(intervalMs, iGnssMeasurement, callback);
+
+        StartAndCheckFirstLocation(locationIntervalMs, /* lowPowerMode= */ false);
+        std::vector<int> deltas;
+        collectMeasurementIntervals(callback, /*numEvents=*/10, /*timeoutSeconds=*/10, deltas);
+
+        StopAndClearLocations();
+        status = iGnssMeasurement->close();
+        ASSERT_TRUE(status.isOk());
+
+        assertMeanAndStdev(locationIntervalMs, deltas);
+    }
+}
diff --git a/gnss/common/utils/default/include/Utils.h b/gnss/common/utils/default/include/Utils.h
index 7065a6fb..ad8f539 100644
--- a/gnss/common/utils/default/include/Utils.h
+++ b/gnss/common/utils/default/include/Utils.h
@@ -56,6 +56,31 @@
     static hidl_vec<V2_1::IGnssAntennaInfoCallback::GnssAntennaInfo> getMockAntennaInfos();
 };
 
+struct ThreadBlocker {
+    // returns false if unblocked:
+    template <class R, class P>
+    bool wait_for(std::chrono::duration<R, P> const& time) {
+        std::unique_lock<std::mutex> lock(m);
+        return !cv.wait_for(lock, time, [&] { return terminate; });
+    }
+
+    void notify() {
+        std::unique_lock<std::mutex> lock(m);
+        terminate = true;
+        cv.notify_all();
+    }
+
+    void reset() {
+        std::unique_lock<std::mutex> lock(m);
+        terminate = false;
+    }
+
+  private:
+    std::condition_variable cv;
+    std::mutex m;
+    bool terminate = false;
+};
+
 }  // namespace common
 }  // namespace gnss
 }  // namespace hardware
diff --git a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
index c9d058d..59af5cf 100644
--- a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
+++ b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
@@ -153,7 +153,6 @@
             if (error == EX_SERVICE_SPECIFIC) {
                 error = status.getServiceSpecificError();
                 EXPECT_NE(OK, error) << "Failed to set error properly";
-                EXPECT_EQ(OK, error) << "Failed to allocate";
             } else {
                 EXPECT_EQ(OK, error) << "Allocation transport failure";
             }
@@ -278,6 +277,7 @@
     if (!supported) {
         ASSERT_EQ(nullptr, buffer.get())
                 << "Allocation succeeded, but IMapper::isSupported was false";
+        GTEST_SKIP();
     } else {
         ASSERT_NE(nullptr, buffer.get()) << "Allocation failed, but IMapper::isSupported was true";
     }
@@ -319,6 +319,7 @@
     if (!supported) {
         ASSERT_EQ(nullptr, buffer.get())
                 << "Allocation succeeded, but IMapper::isSupported was false";
+        GTEST_SKIP();
     } else {
         ASSERT_NE(nullptr, buffer.get()) << "Allocation failed, but IMapper::isSupported was true";
     }
@@ -375,4 +376,4 @@
         [](auto info) -> std::string {
             std::string name = std::to_string(info.index) + "/" + std::get<2>(info.param).name;
             return Sanitize(name);
-        });
\ No newline at end of file
+        });
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp b/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
index 0171dd6..3527cca 100644
--- a/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
+++ b/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
@@ -25,7 +25,6 @@
     name: "libhwc2on1adapter",
     vendor: true,
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp b/graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp
index 3965d12..d613ba9 100644
--- a/graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp
+++ b/graphics/composer/2.1/utils/hwc2onfbadapter/Android.bp
@@ -25,7 +25,6 @@
     name: "libhwc2onfbadapter",
     vendor: true,
 
-    clang: true,
     cflags: [
         "-Wall",
         "-Wextra",
@@ -37,6 +36,9 @@
     ],
 
     header_libs: ["libhardware_headers"],
-    shared_libs: ["liblog", "libsync"],
+    shared_libs: [
+        "liblog",
+        "libsync",
+    ],
     export_include_dirs: ["include"],
 }
diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp
index 8732d53..c0a0c07 100644
--- a/graphics/composer/2.1/utils/vts/Android.bp
+++ b/graphics/composer/2.1/utils/vts/Android.bp
@@ -32,6 +32,7 @@
         "TestCommandReader.cpp",
     ],
     static_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.mapper@2.0-vts",
         "android.hardware.graphics.mapper@3.0-vts",
@@ -39,6 +40,7 @@
         "libgtest",
     ],
     export_static_lib_headers: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.mapper@2.0-vts",
         "android.hardware.graphics.mapper@3.0-vts",
diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
index 55aaf12..4603dd1 100644
--- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -316,9 +316,13 @@
 
 Gralloc::Gralloc() {
     [this] {
-        ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>("default", "default",
-                                                                       /*errOnFailure=*/false));
-        if (mGralloc4->getAllocator() == nullptr || mGralloc4->getMapper() == nullptr) {
+        ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>(
+                                        /*aidlAllocatorServiceName*/ IAllocator::descriptor +
+                                                std::string("/default"),
+                                        /*hidlAllocatorServiceName*/ "default",
+                                        /*mapperServiceName*/ "default",
+                                        /*errOnFailure=*/false));
+        if (!mGralloc4->hasAllocator() || mGralloc4->getMapper() == nullptr) {
             mGralloc4 = nullptr;
             ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
                                                                            /*errOnFailure=*/false));
diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
index 2949823..f8ea661 100644
--- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
+++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
@@ -49,6 +49,7 @@
 using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc;
 using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc;
 using Gralloc4 = android::hardware::graphics::mapper::V4_0::vts::Gralloc;
+using IAllocator = aidl::android::hardware::graphics::allocator::IAllocator;
 
 class ComposerClient;
 
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index 9ffd7d5..502036e 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -32,14 +32,17 @@
     // TODO(b/64437680): Assume these libs are always available on the device.
     shared_libs: [
         "libbase",
+        "libbinder_ndk",
         "libfmq",
         "libsync",
+        "android.hardware.common-V2-ndk",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.1",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@4.0",
     ],
     static_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.allocator@4.0",
@@ -49,10 +52,14 @@
         "android.hardware.graphics.mapper@2.1-vts",
         "android.hardware.graphics.mapper@3.0-vts",
         "android.hardware.graphics.mapper@4.0-vts",
+        "libaidlcommonsupport",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
     ],
     disable_framework: true,
-    test_suites: ["general-tests", "vts"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index aa8e541..cca5323 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -35,6 +35,7 @@
         "libui",
     ],
     static_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer3-V1-ndk",
@@ -52,6 +53,7 @@
         "android.hardware.graphics.mapper@4.0-vts",
     ],
     export_static_lib_headers: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.mapper@2.1-vts",
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index a526137..b706596 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -182,9 +182,13 @@
 Gralloc::Gralloc() {
     [this] {
         ALOGD("Attempting to initialize gralloc4");
-        ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>("default", "default",
-                                                                       /*errOnFailure=*/false));
-        if (mGralloc4->getMapper() == nullptr || mGralloc4->getAllocator() == nullptr) {
+        ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>(
+                                        /*aidlAllocatorServiceName*/ IAllocator::descriptor +
+                                                std::string("/default"),
+                                        /*hidlAllocatorServiceName*/ "default",
+                                        /*mapperServiceName*/ "default",
+                                        /*errOnFailure=*/false));
+        if (mGralloc4->getMapper() == nullptr || !mGralloc4->hasAllocator()) {
             mGralloc4 = nullptr;
             ALOGD("Failed to initialize gralloc4, initializing gralloc3");
             ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
index d3bba17..02d7bdb 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
@@ -48,6 +48,7 @@
 using Gralloc2_1 = android::hardware::graphics::mapper::V2_1::vts::Gralloc;
 using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc;
 using Gralloc4 = android::hardware::graphics::mapper::V4_0::vts::Gralloc;
+using IAllocator = aidl::android::hardware::graphics::allocator::IAllocator;
 
 class ComposerClient;
 
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index dd519e7..960b62d 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -45,18 +45,21 @@
         "libGLESv1_CM",
         "libGLESv2",
         "libbase",
+        "libbinder_ndk",
         "libfmq",
         "libgui",
         "libhidlbase",
         "libprocessgroup",
         "libsync",
         "libui",
+        "android.hardware.common-V2-ndk",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.1",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@4.0",
     ],
     static_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.allocator@4.0",
@@ -70,6 +73,7 @@
         "android.hardware.graphics.mapper@2.1-vts",
         "android.hardware.graphics.mapper@3.0-vts",
         "android.hardware.graphics.mapper@4.0-vts",
+        "libaidlcommonsupport",
         "libgtest",
         "librenderengine",
         "libshaders",
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
index 70384ac..40b77d5 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -32,15 +32,18 @@
     // TODO(b/64437680): Assume these libs are always available on the device.
     shared_libs: [
         "libbase",
+        "libbinder_ndk",
         "libfmq",
         "libhidlbase",
         "libsync",
+        "android.hardware.common-V2-ndk",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.1",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@4.0",
     ],
     static_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.allocator@4.0",
@@ -54,6 +57,7 @@
         "android.hardware.graphics.mapper@2.1-vts",
         "android.hardware.graphics.mapper@3.0-vts",
         "android.hardware.graphics.mapper@4.0-vts",
+        "libaidlcommonsupport",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
@@ -61,5 +65,8 @@
         "android.hardware.graphics.composer@2.3-command-buffer",
     ],
     disable_framework: true,
-    test_suites: ["general-tests", "vts"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/graphics/composer/2.4/utils/vts/Android.bp b/graphics/composer/2.4/utils/vts/Android.bp
index 5ef861c..de31975 100644
--- a/graphics/composer/2.4/utils/vts/Android.bp
+++ b/graphics/composer/2.4/utils/vts/Android.bp
@@ -32,6 +32,7 @@
         "TestCommandReader.cpp",
     ],
     static_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.3-vts",
diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp
index 22ae7c4..b73ea94 100644
--- a/graphics/composer/2.4/vts/functional/Android.bp
+++ b/graphics/composer/2.4/vts/functional/Android.bp
@@ -32,14 +32,17 @@
     // TODO(b/64437680): Assume these libs are always available on the device.
     shared_libs: [
         "libbase",
+        "libbinder_ndk",
         "libfmq",
         "libsync",
+        "android.hardware.common-V2-ndk",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.1",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@4.0",
     ],
     static_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.allocator@4.0",
@@ -55,6 +58,7 @@
         "android.hardware.graphics.mapper@2.1-vts",
         "android.hardware.graphics.mapper@3.0-vts",
         "android.hardware.graphics.mapper@4.0-vts",
+        "libaidlcommonsupport",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
@@ -63,5 +67,8 @@
         "android.hardware.graphics.composer@2.4-command-buffer",
     ],
     disable_framework: true,
-    test_suites: ["general-tests", "vts"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index ece1fd3..93b646f 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -1719,10 +1719,10 @@
             }
         }
 
+        configureLayer(display, layer, Composition::DISPLAY_DECORATION, display.getFrameRect(),
+                          display.getCrop());
         mWriter.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, decorBuffer->handle,
                                /*acquireFence*/ -1);
-        mWriter.setLayerCompositionType(display.getDisplayId(), layer,
-                                        Composition::DISPLAY_DECORATION);
         mWriter.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         if (support) {
diff --git a/graphics/mapper/4.0/utils/vts/Android.bp b/graphics/mapper/4.0/utils/vts/Android.bp
index 6331498..7abf5db 100644
--- a/graphics/mapper/4.0/utils/vts/Android.bp
+++ b/graphics/mapper/4.0/utils/vts/Android.bp
@@ -32,14 +32,21 @@
         "-g",
     ],
     static_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.allocator@4.0",
+        "android.hardware.graphics.common-V3-ndk",
         "android.hardware.graphics.mapper@4.0",
+        "libaidlcommonsupport",
     ],
     shared_libs: [
+        "libbinder_ndk",
         "libgralloctypes",
+        "libvndksupport",
     ],
     export_static_lib_headers: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.allocator@4.0",
+        "android.hardware.graphics.common-V3-ndk",
         "android.hardware.graphics.mapper@4.0",
     ],
     export_include_dirs: ["include"],
diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
index 4a6f68d..c6c9834 100644
--- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
+#include <aidlcommonsupport/NativeHandle.h>
 #include <android-base/properties.h>
+#include <android/binder_manager.h>
 #include <gralloctypes/Gralloc4.h>
 #include <mapper-vts/4.0/MapperVts.h>
 
@@ -25,27 +27,42 @@
 namespace V4_0 {
 namespace vts {
 
-Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName,
+Gralloc::Gralloc(const std::string& aidlAllocatorServiceName,
+                 const std::string& hidlAllocatorServiceName, const std::string& mapperServiceName,
                  bool errOnFailure) {
     if (errOnFailure) {
-        init(allocatorServiceName, mapperServiceName);
+        init(aidlAllocatorServiceName, hidlAllocatorServiceName, mapperServiceName);
     } else {
-        initNoErr(allocatorServiceName, mapperServiceName);
+        initNoErr(aidlAllocatorServiceName, hidlAllocatorServiceName, mapperServiceName);
     }
 }
 
-void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) {
-    mAllocator = IAllocator::getService(allocatorServiceName);
-    ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
+void Gralloc::init(const std::string& aidlAllocatorServiceName,
+                   const std::string& hidlAllocatorServiceName,
+                   const std::string& mapperServiceName) {
+    mAidlAllocator = aidl::android::hardware::graphics::allocator::IAllocator::fromBinder(
+            ndk::SpAIBinder(AServiceManager_checkService(aidlAllocatorServiceName.c_str())));
+
+    if (mAidlAllocator == nullptr) {
+        mHidlAllocator = IAllocator::getService(hidlAllocatorServiceName);
+    }
+    ASSERT_TRUE(nullptr != mAidlAllocator || mHidlAllocator != nullptr)
+            << "failed to get allocator service";
 
     mMapper = IMapper::getService(mapperServiceName);
     ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
     ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
 }
 
-void Gralloc::initNoErr(const std::string& allocatorServiceName,
+void Gralloc::initNoErr(const std::string& aidlAllocatorServiceName,
+                        const std::string& hidlAllocatorServiceName,
                         const std::string& mapperServiceName) {
-    mAllocator = IAllocator::getService(allocatorServiceName);
+    mAidlAllocator = aidl::android::hardware::graphics::allocator::IAllocator::fromBinder(
+            ndk::SpAIBinder(AServiceManager_checkService(aidlAllocatorServiceName.c_str())));
+
+    if (mAidlAllocator == nullptr) {
+        mHidlAllocator = IAllocator::getService(hidlAllocatorServiceName);
+    }
 
     mMapper = IMapper::getService(mapperServiceName);
     if (mMapper.get()) {
@@ -68,10 +85,6 @@
     mImportedBuffers.clear();
 }
 
-sp<IAllocator> Gralloc::getAllocator() const {
-    return mAllocator;
-}
-
 const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle,
                                             enum Tolerance /*tolerance*/) {
     const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
@@ -90,40 +103,40 @@
                                                       uint32_t* outStride) {
     std::vector<const native_handle_t*> bufferHandles;
     bufferHandles.reserve(count);
-    mAllocator->allocate(descriptor, count,
-                         [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
-                             if (canTolerate(tolerance, tmpError)) {
-                                 return;
-                             }
 
-                             if (tmpError != Error::NONE) {
-                                 if (base::GetIntProperty("ro.vendor.build.version.sdk", 0, 0,
-                                                          INT_MAX) < 33) {
-                                     GTEST_SKIP() << "Old vendor grallocs may not support P010";
-                                 } else {
-                                     GTEST_FAIL() << "failed to allocate buffers";
-                                 }
-                             }
-                             ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array";
+    auto callback = [&](Error error, uint32_t stride,
+                        const hidl_vec<hidl_handle>& buffers) -> void {
+        if (canTolerate(tolerance, error)) {
+            return;
+        }
 
-                             for (uint32_t i = 0; i < count; i++) {
-                                 const native_handle_t* bufferHandle = nullptr;
-                                 if (import) {
-                                     ASSERT_NO_FATAL_FAILURE(
-                                             bufferHandle = importBuffer(tmpBuffers[i], tolerance));
-                                 } else {
-                                     ASSERT_NO_FATAL_FAILURE(
-                                             bufferHandle = cloneBuffer(tmpBuffers[i], tolerance));
-                                 }
-                                 if (bufferHandle) {
-                                     bufferHandles.push_back(bufferHandle);
-                                 }
-                             }
+        if (error != Error::NONE) {
+            if (base::GetIntProperty("ro.vendor.build.version.sdk", 0, 0, INT_MAX) < 33) {
+                GTEST_SKIP() << "Old vendor grallocs may not support P010";
+            } else {
+                GTEST_FAIL() << "failed to allocate buffers";
+            }
+        }
+        ASSERT_EQ(count, buffers.size()) << "invalid buffer array";
 
-                             if (outStride) {
-                                 *outStride = tmpStride;
-                             }
-                         });
+        for (uint32_t i = 0; i < count; i++) {
+            const native_handle_t* bufferHandle = nullptr;
+            if (import) {
+                ASSERT_NO_FATAL_FAILURE(bufferHandle = importBuffer(buffers[i], tolerance));
+            } else {
+                ASSERT_NO_FATAL_FAILURE(bufferHandle = cloneBuffer(buffers[i], tolerance));
+            }
+            if (bufferHandle) {
+                bufferHandles.push_back(bufferHandle);
+            }
+        }
+
+        if (outStride) {
+            *outStride = stride;
+        }
+    };
+
+    rawAllocate(descriptor, count, callback);
 
     if (::testing::Test::HasFatalFailure()) {
         bufferHandles.clear();
@@ -147,6 +160,23 @@
     return buffers[0];
 }
 
+void Gralloc::rawAllocate(
+        const BufferDescriptor& descriptor, uint32_t count,
+        std::function<void(Error, uint32_t, const hidl_vec<hidl_handle>&)> callback) {
+    if (mAidlAllocator) {
+        aidl::android::hardware::graphics::allocator::AllocationResult result;
+        auto status = mAidlAllocator->allocate(descriptor, count, &result);
+        const Error error = toHidlError(status);
+        std::vector<hidl_handle> handles;
+        for (const auto& aidlHandle : result.buffers) {
+            handles.push_back(hidl_handle(makeFromAidl(aidlHandle)));
+        }
+        callback(error, result.stride, handles);
+    } else {
+        mHidlAllocator->allocate(descriptor, count, callback);
+    }
+}
+
 sp<IMapper> Gralloc::getMapper() const {
     return mMapper;
 }
diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
index c5406c9..ecbbc58 100644
--- a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
+++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
@@ -20,6 +20,8 @@
 #include <unordered_set>
 #include <vector>
 
+#include <aidl/android/hardware/graphics/allocator/AllocationError.h>
+#include <aidl/android/hardware/graphics/allocator/IAllocator.h>
 #include <android/hardware/graphics/allocator/4.0/IAllocator.h>
 #include <android/hardware/graphics/mapper/4.0/IMapper.h>
 #include <gtest/gtest.h>
@@ -47,13 +49,39 @@
         kToleranceAllErrors = ~0x0U,
     };
 
-    Gralloc(const std::string& allocatorServiceName = "default",
+    Gralloc(const std::string& aidlAllocatorServiceName =
+                    "android.hardware.graphics.allocator.IAllocator/default",
+            const std::string& hidlAllocatorServiceName = "default",
             const std::string& mapperServiceName = "default", bool errOnFailure = true);
     ~Gralloc();
 
+    static Error toHidlError(aidl::android::hardware::graphics::allocator::AllocationError error) {
+        switch (error) {
+            case aidl::android::hardware::graphics::allocator::AllocationError::BAD_DESCRIPTOR:
+                return Error::BAD_DESCRIPTOR;
+            case aidl::android::hardware::graphics::allocator::AllocationError::NO_RESOURCES:
+                return Error::NO_RESOURCES;
+            case aidl::android::hardware::graphics::allocator::AllocationError::UNSUPPORTED:
+                return Error::UNSUPPORTED;
+        }
+    }
+    static Error toHidlError(const ndk::ScopedAStatus& status) {
+        if (status.isOk()) {
+            return Error::NONE;
+        }
+
+        if (status.getExceptionCode() != EX_SERVICE_SPECIFIC) {
+            return Error::NO_RESOURCES;
+        }
+
+        return toHidlError(
+                static_cast<aidl::android::hardware::graphics::allocator::AllocationError>(
+                        status.getServiceSpecificError()));
+    }
+
     // IAllocator methods
 
-    sp<IAllocator> getAllocator() const;
+    bool hasAllocator() { return mHidlAllocator != nullptr || mAidlAllocator != nullptr; }
 
     // When import is false, this simply calls IAllocator::allocate. When import
     // is true, the returned buffers are also imported into the mapper.
@@ -81,6 +109,10 @@
         return allocate(descriptorInfo, import, Tolerance::kToleranceStrict, outStride);
     }
 
+    // Dispatches directly to the allocator
+    void rawAllocate(const BufferDescriptor& descriptor, uint32_t count,
+                     std::function<void(Error, uint32_t, const hidl_vec<hidl_handle>&)> callback);
+
     // IMapper methods
 
     sp<IMapper> getMapper() const;
@@ -134,16 +166,20 @@
                 0x1U << std::underlying_type_t<Error>(error)) != 0;
     }
 
-    void init(const std::string& allocatorServiceName, const std::string& mapperServiceName);
+    void init(const std::string& aidlAllocatorServiceName,
+              const std::string& hidlAllocatorServiceName, const std::string& mapperServiceName);
 
     // initialize without checking for failure to get service
-    void initNoErr(const std::string& allocatorServiceName, const std::string& mapperServiceName);
+    void initNoErr(const std::string& aidlAllocatorServiceName,
+                   const std::string& hidlAllocatorServiceName,
+                   const std::string& mapperServiceName);
     const native_handle_t* cloneBuffer(const hidl_handle& rawHandle, enum Tolerance tolerance);
     const native_handle_t* cloneBuffer(const hidl_handle& rawHandle) {
         return cloneBuffer(rawHandle, Tolerance::kToleranceStrict);
     }
 
-    sp<IAllocator> mAllocator;
+    sp<IAllocator> mHidlAllocator;
+    std::shared_ptr<aidl::android::hardware::graphics::allocator::IAllocator> mAidlAllocator;
     sp<IMapper> mMapper;
 
     // Keep track of all cloned and imported handles.  When a test fails with
diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp
index 65bc380..e830633 100644
--- a/graphics/mapper/4.0/vts/functional/Android.bp
+++ b/graphics/mapper/4.0/vts/functional/Android.bp
@@ -25,20 +25,27 @@
 
 cc_test {
     name: "VtsHalGraphicsMapperV4_0TargetTest",
-    defaults: ["VtsHalTargetTestDefaults"],
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
     srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"],
     static_libs: [
         "android.hardware.graphics.common-V3-ndk",
         "android.hardware.graphics.mapper@4.0-vts",
+        "libaidlcommonsupport",
         "libgralloctypes",
         "libsync",
     ],
     shared_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.common@1.0",
         "android.hardware.graphics.common@1.1",
         "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.mapper@4.0",
+        "libbinder_ndk",
+        "libvndksupport",
     ],
     header_libs: [
         "libsystem_headers",
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 8f440e4..5a450e3 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -21,8 +21,12 @@
 #include <thread>
 #include <vector>
 
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/graphics/allocator/AllocationError.h>
+#include <aidl/android/hardware/graphics/allocator/AllocationResult.h>
 #include <aidl/android/hardware/graphics/common/PixelFormat.h>
 #include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
+#include <aidlcommonsupport/NativeHandle.h>
 
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
@@ -72,7 +76,7 @@
     void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
                                                                      std::get<1>(GetParam())));
-        ASSERT_NE(nullptr, mGralloc->getAllocator().get());
+        ASSERT_TRUE(mGralloc->hasAllocator());
         ASSERT_NE(nullptr, mGralloc->getMapper().get());
 
         mDummyDescriptorInfo.name = "dummy";
@@ -504,10 +508,10 @@
 TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
     // this assumes any valid descriptor is non-empty
     BufferDescriptor descriptor;
-    mGralloc->getAllocator()->allocate(descriptor, 1,
-                                       [&](const auto& tmpError, const auto&, const auto&) {
-                                           EXPECT_EQ(Error::BAD_DESCRIPTOR, tmpError);
-                                       });
+
+    mGralloc->rawAllocate(descriptor, 1, [&](const auto& tmpError, const auto&, const auto&) {
+        EXPECT_EQ(Error::BAD_DESCRIPTOR, tmpError);
+    });
 }
 
 /**
@@ -535,9 +539,9 @@
     std::atomic<uint64_t> allocationCount(0);
     auto threadLoop = [&]() {
         while (!timeUp) {
-            mGralloc->getAllocator()->allocate(
-                    descriptor, 1,
-                    [&](const auto&, const auto&, const auto&) { allocationCount++; });
+            mGralloc->rawAllocate(descriptor, 1, [&](const auto&, const auto&, const auto&) {
+                allocationCount++;
+            });
         }
     };
 
@@ -2212,6 +2216,11 @@
               mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec));
     ASSERT_EQ(Error::UNSUPPORTED,
               mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec));
+
+    // Keep optional metadata types below and populate the encoded metadata vec
+    // with some arbitrary different metadata because the common gralloc4::decode*()
+    // functions do not distinguish between an empty vec and bad value.
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(Dataspace::SRGB_LINEAR, &vec));
     ASSERT_EQ(Error::UNSUPPORTED,
               mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec));
     ASSERT_EQ(Error::UNSUPPORTED,
@@ -2750,8 +2759,9 @@
         BufferDescriptor descriptor;
         ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(info));
 
-        Error err;
-        mGralloc->getAllocator()->allocate(
+        Error err = Error::NONE;
+
+        mGralloc->rawAllocate(
                 descriptor, 1, [&](const auto& tmpError, const auto&, const auto& tmpBuffers) {
                     err = tmpError;
                     if (err == Error::NONE) {
@@ -2822,11 +2832,27 @@
 }
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsMapperHidlTest);
+
+namespace {
+std::vector<std::string> getAllocatorInstances() {
+    std::vector<std::string> instances;
+    for (auto halInstance : android::hardware::getAllHalInstanceNames(IAllocator::descriptor)) {
+        instances.emplace_back(std::move(halInstance));
+    }
+
+    for (auto aidlInstance : getAidlHalInstanceNames(
+                 aidl::android::hardware::graphics::allocator::IAllocator::descriptor)) {
+        instances.emplace_back(std::move(aidlInstance));
+    }
+
+    return instances;
+}
+}  // namespace
+
 INSTANTIATE_TEST_CASE_P(
         PerInstance, GraphicsMapperHidlTest,
         testing::Combine(
-                testing::ValuesIn(
-                        android::hardware::getAllHalInstanceNames(IAllocator::descriptor)),
+                testing::ValuesIn(getAllocatorInstances()),
                 testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMapper::descriptor))),
         android::hardware::PrintInstanceTupleNameToString<>);
 
diff --git a/health/aidl/Android.bp b/health/aidl/Android.bp
index f0cd33f..a4d4ace 100644
--- a/health/aidl/Android.bp
+++ b/health/aidl/Android.bp
@@ -36,11 +36,6 @@
             enabled: true,
             sdk_version: "module_current",
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
diff --git a/health/aidl/default/Android.bp b/health/aidl/default/Android.bp
index 8eab997..0d426da 100644
--- a/health/aidl/default/Android.bp
+++ b/health/aidl/default/Android.bp
@@ -159,3 +159,70 @@
     init_rc: ["android.hardware.health-service.example_recovery.rc"],
     overrides: ["charger.recovery"],
 }
+
+// AIDL Fuzz version of libhealth2impl.
+cc_library_static {
+    name: "fuzz_libhealth_aidl_impl",
+    defaults: [
+        "libhealth_aidl_common_defaults",
+        "libhealth_aidl_charger_defaults",
+    ],
+    recovery_available: true,
+    export_include_dirs: ["include"],
+    export_static_lib_headers: [
+        "libbatterymonitor",
+    ],
+    srcs: [
+        "ChargerUtils.cpp",
+        "health-convert.cpp",
+        "HalHealthLoop.cpp",
+        "Health.cpp",
+        "LinkedCallback.cpp",
+    ],
+    target: {
+        recovery: {
+            exclude_srcs: [
+                "ChargerUtils.cpp",
+            ],
+        },
+    },
+}
+
+cc_fuzz {
+    name: "android.hardware.health-service.aidl_fuzzer",
+    defaults: [
+        "libhealth_aidl_impl_user",
+    ],
+    static_libs: [
+        "android.hardware.health-V1-ndk",
+        "libbase",
+        "libbinder_random_parcel",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "fuzz_libhealth_aidl_impl",
+    ],
+    target: {
+        android: {
+            shared_libs: [
+                "libbinder_ndk",
+                "libbinder",
+            ],
+        },
+        host: {
+            static_libs: [
+                "libbinder_ndk",
+                "libbinder",
+            ],
+        },
+        darwin: {
+            enabled: false,
+        },
+    },
+    srcs: ["fuzzer.cpp"],
+    fuzz_config: {
+        cc: [
+            "hamzeh@google.com",
+        ],
+    },
+}
diff --git a/health/aidl/default/fuzzer.cpp b/health/aidl/default/fuzzer.cpp
new file mode 100644
index 0000000..b7c6d39
--- /dev/null
+++ b/health/aidl/default/fuzzer.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <android-base/logging.h>
+#include <android/binder_interface_utils.h>
+#include <health-impl/Health.h>
+#include <health/utils.h>
+
+using aidl::android::hardware::health::Health;
+using android::fuzzService;
+using ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    auto config = std::make_unique<healthd_config>();
+    ::android::hardware::health::InitHealthdConfig(config.get());
+    auto binder = ndk::SharedRefBase::make<Health>("default", std::move(config));
+
+    fuzzService(binder->asBinder().get(), FuzzedDataProvider(data, size));
+
+    return 0;
+}
\ No newline at end of file
diff --git a/health/storage/aidl/Android.bp b/health/storage/aidl/Android.bp
index 4cd9263..c614efb 100644
--- a/health/storage/aidl/Android.bp
+++ b/health/storage/aidl/Android.bp
@@ -33,11 +33,6 @@
         java: {
             enabled: false,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions: ["1"],
 }
diff --git a/identity/aidl/Android.bp b/identity/aidl/Android.bp
index 920a4b9..f6855e8 100644
--- a/identity/aidl/Android.bp
+++ b/identity/aidl/Android.bp
@@ -23,9 +23,6 @@
             platform_apis: true,
         },
         ndk: {
-            vndk: {
-                enabled: true,
-            },
             apps_enabled: false,
         },
     },
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index fee58a4..51ab110 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -59,16 +59,3 @@
     ],
     require_root: true,
 }
-
-java_test_host {
-    name: "IdentityCredentialImplementedTest",
-    libs: [
-        "tradefed",
-        "vts-core-tradefed-harness",
-    ],
-    srcs: ["src/**/*.java"],
-    test_suites: [
-        "vts",
-    ],
-    test_config: "IdentityCredentialImplementedTest.xml",
-}
diff --git a/identity/aidl/vts/AndroidTest.xml b/identity/aidl/vts/AndroidTest.xml
new file mode 100644
index 0000000..67132b0
--- /dev/null
+++ b/identity/aidl/vts/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VtsHalIdentityTargetTest.">
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push"
+                value="VtsHalIdentityTargetTest->/data/local/tmp/VtsHalIdentityTargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalIdentityTargetTest" />
+        <option name="native-test-timeout" value="300000"/>
+    </test>
+</configuration>
diff --git a/identity/aidl/vts/IdentityCredentialImplementedTest.xml b/identity/aidl/vts/IdentityCredentialImplementedTest.xml
deleted file mode 100644
index 1d76a74..0000000
--- a/identity/aidl/vts/IdentityCredentialImplementedTest.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<configuration description="Runs IdentityCredentialImplementedTest">
-  <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
-
-  <test class="com.android.tradefed.testtype.HostTest" >
-    <option name="jar" value="IdentityCredentialImplementedTest.jar" />
-  </test>
-</configuration>
diff --git a/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java b/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java
deleted file mode 100644
index 19568af..0000000
--- a/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.tests.security.identity;
-
-import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
-
-import android.platform.test.annotations.RequiresDevice;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(DeviceJUnit4ClassRunner.class)
-public class IdentityCredentialImplementedTest extends BaseHostJUnit4Test {
-    // Returns the ro.vendor.api_level or 0 if not set.
-    //
-    // Throws NumberFormatException if ill-formatted.
-    //
-    // Throws DeviceNotAvailableException if device is not available.
-    //
-    private int getVendorApiLevel() throws NumberFormatException, DeviceNotAvailableException {
-        String vendorApiLevelString =
-                getDevice().executeShellCommand("getprop ro.vendor.api_level").trim();
-        if (vendorApiLevelString.isEmpty()) {
-            return 0;
-        }
-        return Integer.parseInt(vendorApiLevelString);
-    }
-
-    // As of Android 13 (API level 32), Identity Credential is required at feature version 202201
-    // or newer.
-    //
-    @RequiresDevice
-    @Test
-    public void testIdentityCredentialIsImplemented() throws Exception {
-        int vendorApiLevel = getVendorApiLevel();
-        assumeTrue(vendorApiLevel >= 32);
-
-        final String minimumFeatureVersionNeeded = "202201";
-
-        String result = getDevice().executeShellCommand(
-                "pm has-feature android.hardware.identity_credential "
-                + minimumFeatureVersionNeeded);
-        if (!result.trim().equals("true")) {
-            fail("Identity Credential feature version " + minimumFeatureVersionNeeded
-                    + " required but not found");
-        }
-    }
-}
diff --git a/ir/aidl/Android.bp b/ir/aidl/Android.bp
index 2485f5b..25f6c8f 100644
--- a/ir/aidl/Android.bp
+++ b/ir/aidl/Android.bp
@@ -33,11 +33,6 @@
         java: {
             sdk_version: "module_current",
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index bf56860..fb5048a 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -27,6 +27,7 @@
 #include <openssl/mem.h>
 #include <openssl/x509.h>
 
+#include <android-base/properties.h>
 #include <cutils/properties.h>
 
 #include <keymasterV4_0/attestation_record.h>
@@ -386,6 +387,31 @@
     return property_get("ro.boot.vbmeta.device_state", value, "") != 0;
 }
 
+int get_vsr_api_level() {
+    int vendor_api_level = ::android::base::GetIntProperty("ro.vendor.api_level", -1);
+    if (vendor_api_level != -1) {
+        return vendor_api_level;
+    }
+
+    // Android S and older devices do not define ro.vendor.api_level
+    vendor_api_level = ::android::base::GetIntProperty("ro.board.api_level", -1);
+    if (vendor_api_level == -1) {
+        vendor_api_level = ::android::base::GetIntProperty("ro.board.first_api_level", -1);
+    }
+
+    int product_api_level = ::android::base::GetIntProperty("ro.product.first_api_level", -1);
+    if (product_api_level == -1) {
+        product_api_level = ::android::base::GetIntProperty("ro.build.version.sdk", -1);
+        EXPECT_NE(product_api_level, -1) << "Could not find ro.build.version.sdk";
+    }
+
+    // VSR API level is the minimum of vendor_api_level and product_api_level.
+    if (vendor_api_level == -1 || vendor_api_level > product_api_level) {
+        return product_api_level;
+    }
+    return vendor_api_level;
+}
+
 bool is_gsi() {
     char property_value[PROPERTY_VALUE_MAX] = {};
     EXPECT_NE(property_get("ro.product.system.name", property_value, ""), 0);
@@ -4833,6 +4859,18 @@
 
 INSTANTIATE_KEYMASTER_HIDL_TEST(TransportLimitTest);
 
+using VsrRequirementTest = KeymasterHidlTest;
+
+TEST_P(VsrRequirementTest, Vsr13Test) {
+    int vsr_api_level = get_vsr_api_level();
+    if (vsr_api_level < 33) {
+        GTEST_SKIP() << "Applies only to VSR API level 33, this device is: " << vsr_api_level;
+    }
+    FAIL() << "VSR 13+ requires KeyMint version 2";
+}
+
+INSTANTIATE_KEYMASTER_HIDL_TEST(VsrRequirementTest);
+
 }  // namespace test
 }  // namespace V4_0
 }  // namespace keymaster
diff --git a/keymaster/aidl/Android.bp b/keymaster/aidl/Android.bp
index c4b6740..0fb6e4c 100644
--- a/keymaster/aidl/Android.bp
+++ b/keymaster/aidl/Android.bp
@@ -18,11 +18,6 @@
         java: {
             platform_apis: true,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions: [
         "1",
diff --git a/light/aidl/Android.bp b/light/aidl/Android.bp
index 6f478d7..c11934f 100644
--- a/light/aidl/Android.bp
+++ b/light/aidl/Android.bp
@@ -18,11 +18,6 @@
         java: {
             sdk_version: "module_current",
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
diff --git a/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp b/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
index 2ae9c2b..00e9837 100755
--- a/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
+++ b/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
@@ -400,9 +400,18 @@
                             << " Component: " << info.mName.c_str() << " Role: " << role.c_str()
                             << " not allowed for devices launching with Android T and above";
                 } else {
-                    ASSERT_LT(getFirstApiLevel(), __ANDROID_API_S__)
+                    std::string codecName = info.mName;
+                    bool isAndroidCodec = (codecName.rfind("OMX.google", 0) != std::string::npos);
+                    if (isAndroidCodec && (getFirstApiLevel() <= __ANDROID_API_S__)) {
+                        // refer b/230582620
+                        // S AOSP build did not remove the OMX.google video codecs
+                        // so it is infeasible to require no OMX.google.* video codecs
+                        // on S launching devices
+                    } else {
+                        ASSERT_LT(getFirstApiLevel(), __ANDROID_API_S__)
                             << " Component: " << info.mName.c_str() << " Role: " << role.c_str()
                             << " not allowed for devices launching with Android S and above";
+                    }
                 }
             }
             if (role.find("audio_decoder") != std::string::npos ||
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index 29b31d2..a41f37f 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -90,7 +90,6 @@
         "libneuralnetworks_headers",
     ],
     test_suites: [
-        "general-tests",
         "vts",
     ],
 }
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index e9d4b76..7c1c118 100644
--- a/neuralnetworks/1.1/vts/functional/Android.bp
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -58,7 +58,6 @@
         "libneuralnetworks_headers",
     ],
     test_suites: [
-        "general-tests",
         "vts",
     ],
 }
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index 2177924..7e4b5bb 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -85,7 +85,6 @@
         "libneuralnetworks_headers",
     ],
     test_suites: [
-        "general-tests",
         "vts",
     ],
 }
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index 3d783d9..fe38e61 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -1262,7 +1262,7 @@
         FILE* pFile = fopen(filename.c_str(), "a");
         uint32_t appendLength = getRandomInt(1, 256);
         for (uint32_t i = 0; i < appendLength; i++) {
-            ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
+            ASSERT_NE(fputc(getRandomInt<uint16_t>(0, 255), pFile), EOF);
         }
         fclose(pFile);
         *skip = false;
diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp
index 9fa0f0a..07071cc 100644
--- a/neuralnetworks/1.3/vts/functional/Android.bp
+++ b/neuralnetworks/1.3/vts/functional/Android.bp
@@ -92,7 +92,6 @@
         "libneuralnetworks_headers",
     ],
     test_suites: [
-        "general-tests",
         "vts",
     ],
 }
diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
index a2013ec..f2cfa3f 100644
--- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
@@ -1253,7 +1253,7 @@
         FILE* pFile = fopen(filename.c_str(), "a");
         uint32_t appendLength = getRandomInt(1, 256);
         for (uint32_t i = 0; i < appendLength; i++) {
-            ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
+            ASSERT_NE(fputc(getRandomInt<uint16_t>(0, 255), pFile), EOF);
         }
         fclose(pFile);
         *skip = false;
diff --git a/neuralnetworks/TEST_MAPPING b/neuralnetworks/TEST_MAPPING
index d296828..3218206 100644
--- a/neuralnetworks/TEST_MAPPING
+++ b/neuralnetworks/TEST_MAPPING
@@ -17,54 +17,10 @@
     },
     {
       "name": "neuralnetworks_utils_hal_aidl_test"
-    },
-    {
-      "name": "VtsHalNeuralnetworksV1_0TargetTest",
-      "options": [
-        {
-          // Do not use any sample driver except sample-all in order to reduce
-          // testing time. The other sample drivers (fast-float, quant, etc.)
-          // are subsets of sample-all.
-          "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
-        }
-      ]
-    },
-    {
-      "name": "VtsHalNeuralnetworksV1_1TargetTest",
-      "options": [
-        {
-          // Do not use any sample driver except sample-all in order to reduce
-          // testing time. The other sample drivers (fast-float, quant, etc.)
-          // are subsets of sample-all.
-          "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
-        }
-      ]
     }
   ],
   "presubmit-large": [
     {
-      "name": "VtsHalNeuralnetworksV1_2TargetTest",
-      "options": [
-        {
-          // Do not use any sample driver except sample-all in order to reduce
-          // testing time. The other sample drivers (fast-float, quant, etc.)
-          // are subsets of sample-all.
-          "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
-        }
-      ]
-    },
-    {
-      "name": "VtsHalNeuralnetworksV1_3TargetTest",
-      "options": [
-        {
-          // Do not use any sample driver except sample-all in order to reduce
-          // testing time. The other sample drivers (fast-float, quant, etc.)
-          // are subsets of sample-all.
-          "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
-        }
-      ]
-    },
-    {
       "name": "VtsHalNeuralnetworksTargetTest",
       "options": [
         {
diff --git a/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
index 7451f7e..da0fe64 100644
--- a/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
@@ -1068,7 +1068,7 @@
         FILE* pFile = fopen(filename.c_str(), "a");
         uint32_t appendLength = getRandomInt(1, 256);
         for (uint32_t i = 0; i < appendLength; i++) {
-            ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
+            ASSERT_NE(fputc(getRandomInt<uint16_t>(0, 255), pFile), EOF);
         }
         fclose(pFile);
         *skip = false;
diff --git a/nfc/aidl/Android.bp b/nfc/aidl/Android.bp
index b9578f4..09a45d1 100644
--- a/nfc/aidl/Android.bp
+++ b/nfc/aidl/Android.bp
@@ -34,11 +34,6 @@
             sdk_version: "module_current",
             enabled: false,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
diff --git a/oemlock/aidl/Android.bp b/oemlock/aidl/Android.bp
index d1930f9..1c19bb1 100644
--- a/oemlock/aidl/Android.bp
+++ b/oemlock/aidl/Android.bp
@@ -16,11 +16,6 @@
         java: {
             platform_apis: true,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions: ["1"],
 }
diff --git a/power/aidl/Android.bp b/power/aidl/Android.bp
index e4708f8..70b1203 100644
--- a/power/aidl/Android.bp
+++ b/power/aidl/Android.bp
@@ -35,11 +35,6 @@
         java: {
             platform_apis: true,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
diff --git a/power/aidl/vts/VtsHalPowerTargetTest.cpp b/power/aidl/vts/VtsHalPowerTargetTest.cpp
index e0ca87f..2cfa04a 100644
--- a/power/aidl/vts/VtsHalPowerTargetTest.cpp
+++ b/power/aidl/vts/VtsHalPowerTargetTest.cpp
@@ -211,19 +211,6 @@
     }
 }
 
-// GAME_LOADING mode is required for all devices which ship on Android T
-// or later
-TEST_P(PowerAidl, hasGameLoading) {
-    auto apiLevel = GetUintProperty<uint64_t>("ro.vendor.api_level", 0);
-    ASSERT_NE(apiLevel, 0);
-
-    if (apiLevel >= 33) {
-        bool supported;
-        ASSERT_TRUE(power->isModeSupported(Mode::GAME_LOADING, &supported).isOk());
-        ASSERT_TRUE(supported);
-    }
-}
-
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PowerAidl);
 INSTANTIATE_TEST_SUITE_P(Power, PowerAidl,
                          testing::ValuesIn(::android::getAidlHalInstanceNames(IPower::descriptor)),
diff --git a/power/stats/aidl/Android.bp b/power/stats/aidl/Android.bp
index 48d3c51..b1b2515 100644
--- a/power/stats/aidl/Android.bp
+++ b/power/stats/aidl/Android.bp
@@ -32,11 +32,6 @@
         java: {
             platform_apis: true,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
         cpp: {
             enabled: true,
         },
diff --git a/radio/aidl/Android.bp b/radio/aidl/Android.bp
index 19f81f7..c0609d8 100644
--- a/radio/aidl/Android.bp
+++ b/radio/aidl/Android.bp
@@ -20,11 +20,6 @@
         java: {
             sdk_version: "module_current",
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
@@ -49,11 +44,6 @@
         java: {
             sdk_version: "module_current",
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
@@ -78,11 +68,6 @@
         java: {
             sdk_version: "module_current",
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
@@ -107,11 +92,6 @@
         java: {
             sdk_version: "module_current",
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
@@ -136,11 +116,6 @@
         java: {
             sdk_version: "module_current",
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
@@ -165,11 +140,6 @@
         java: {
             sdk_version: "module_current",
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
@@ -197,11 +167,6 @@
         java: {
             sdk_version: "module_current",
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
@@ -229,11 +194,6 @@
         java: {
             sdk_version: "module_current",
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/1/.hash b/radio/aidl/aidl_api/android.hardware.radio.config/1/.hash
index 4d5fc89..960539d 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/1/.hash
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/1/.hash
@@ -1 +1,2 @@
 6e0b1fb58d66a76df8f46a1a6dae5c346ea17d7b
+dd9c3f8e21930f9b4c46a4125bd5f5cec90318ec
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/1/android/hardware/radio/config/PhoneCapability.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/1/android/hardware/radio/config/PhoneCapability.aidl
index c60200c..db3a4c6 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/1/android/hardware/radio/config/PhoneCapability.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/1/android/hardware/radio/config/PhoneCapability.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.config;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable PhoneCapability {
   byte maxActiveData;
   byte maxActiveInternetData;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/1/android/hardware/radio/config/SimPortInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/1/android/hardware/radio/config/SimPortInfo.aidl
index 5cc9017..b5d31ad 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/1/android/hardware/radio/config/SimPortInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/1/android/hardware/radio/config/SimPortInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.config;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable SimPortInfo {
   String iccId;
   int logicalSlotId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/1/android/hardware/radio/config/SimSlotStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/1/android/hardware/radio/config/SimSlotStatus.aidl
index bc7f63c..be4c080 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/1/android/hardware/radio/config/SimSlotStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/1/android/hardware/radio/config/SimSlotStatus.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.config;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable SimSlotStatus {
   int cardState;
   String atr;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/1/android/hardware/radio/config/SlotPortMapping.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/1/android/hardware/radio/config/SlotPortMapping.aidl
index f38c421..31271ee 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/1/android/hardware/radio/config/SlotPortMapping.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/1/android/hardware/radio/config/SlotPortMapping.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.config;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable SlotPortMapping {
   int physicalSlotId;
   int portId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/.hash b/radio/aidl/aidl_api/android.hardware.radio.data/1/.hash
index 986768a..0c0c936 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/.hash
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/.hash
@@ -1 +1,2 @@
 21e60e4149e36bed0fe2af962995f021e88a1da7
+6d7a86008ea4fe79ced2a86b526a92618eb4c84a
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/ApnAuthType.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/ApnAuthType.aidl
index 929cfe3..86272c2 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/ApnAuthType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/ApnAuthType.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum ApnAuthType {
   NO_PAP_NO_CHAP = 0,
   PAP_NO_CHAP = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/ApnTypes.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/ApnTypes.aidl
index 980b042..1518a57 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/ApnTypes.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/ApnTypes.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum ApnTypes {
   NONE = 0,
   DEFAULT = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/DataCallFailCause.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/DataCallFailCause.aidl
index 6130e71..d7d6983 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/DataCallFailCause.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/DataCallFailCause.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum DataCallFailCause {
   NONE = 0,
   OPERATOR_BARRED = 8,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/DataProfileInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/DataProfileInfo.aidl
index 02bbf21..16fada1 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/DataProfileInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/DataProfileInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable DataProfileInfo {
   int profileId;
   String apn;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/DataRequestReason.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/DataRequestReason.aidl
index c94fa6f..0ddaff1 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/DataRequestReason.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/DataRequestReason.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum DataRequestReason {
   NORMAL = 1,
   SHUTDOWN = 2,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/DataThrottlingAction.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/DataThrottlingAction.aidl
index c0ade45..4f976cd 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/DataThrottlingAction.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/DataThrottlingAction.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@Backing(type="byte") @VintfStability
+@Backing(type="byte") @JavaDerive(toString=true) @VintfStability
 enum DataThrottlingAction {
   NO_DATA_THROTTLING = 0,
   THROTTLE_SECONDARY_CARRIER = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/EpsQos.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/EpsQos.aidl
index 3636731..5b9aaa0 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/EpsQos.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/EpsQos.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable EpsQos {
   int qci;
   android.hardware.radio.data.QosBandwidth downlink;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/KeepaliveRequest.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/KeepaliveRequest.aidl
index 788adfb..592a54a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/KeepaliveRequest.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/KeepaliveRequest.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable KeepaliveRequest {
   int type;
   byte[] sourceAddress;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/KeepaliveStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/KeepaliveStatus.aidl
index 4729b8e..82b0fc8 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/KeepaliveStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/KeepaliveStatus.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable KeepaliveStatus {
   int sessionHandle;
   int code;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/LinkAddress.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/LinkAddress.aidl
index 9aee44c..48e646e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/LinkAddress.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/LinkAddress.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable LinkAddress {
   String address;
   int addressProperties;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/NrQos.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/NrQos.aidl
index a8a1696..62f6204 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/NrQos.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/NrQos.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable NrQos {
   int fiveQi;
   android.hardware.radio.data.QosBandwidth downlink;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/OsAppId.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/OsAppId.aidl
index 205b1e9..8595d52 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/OsAppId.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/OsAppId.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable OsAppId {
   byte[] osAppId;
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/PcoDataInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/PcoDataInfo.aidl
index edfa759..033b12f 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/PcoDataInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/PcoDataInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable PcoDataInfo {
   int cid;
   String bearerProto;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/PdpProtocolType.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/PdpProtocolType.aidl
index 363cdf3..9771e5c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/PdpProtocolType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/PdpProtocolType.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum PdpProtocolType {
   UNKNOWN = -1,
   IP = 0,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/PortRange.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/PortRange.aidl
index f3749ed..470a9c1 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/PortRange.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/PortRange.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable PortRange {
   int start;
   int end;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/Qos.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/Qos.aidl
index 1981721..ca06e41 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/Qos.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/Qos.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 union Qos {
   boolean noinit;
   android.hardware.radio.data.EpsQos eps;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosBandwidth.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosBandwidth.aidl
index d7ebe10..6d4b7a9 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosBandwidth.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosBandwidth.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable QosBandwidth {
   int maxBitrateKbps;
   int guaranteedBitrateKbps;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosFilter.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosFilter.aidl
index b9098f7..e22b359 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosFilter.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosFilter.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable QosFilter {
   String[] localAddresses;
   String[] remoteAddresses;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosFilterIpsecSpi.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosFilterIpsecSpi.aidl
index 565e499..4b75340 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosFilterIpsecSpi.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosFilterIpsecSpi.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 union QosFilterIpsecSpi {
   boolean noinit;
   int value;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosFilterIpv6FlowLabel.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosFilterIpv6FlowLabel.aidl
index 16117b2..3fb34ea 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosFilterIpv6FlowLabel.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosFilterIpv6FlowLabel.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 union QosFilterIpv6FlowLabel {
   boolean noinit;
   int value;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosFilterTypeOfService.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosFilterTypeOfService.aidl
index 95fda16..fa85b5a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosFilterTypeOfService.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosFilterTypeOfService.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 union QosFilterTypeOfService {
   boolean noinit;
   byte value;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosSession.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosSession.aidl
index 53dcef0..bbfdd2d 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosSession.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/QosSession.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable QosSession {
   int qosSessionId;
   android.hardware.radio.data.Qos qos;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/RouteSelectionDescriptor.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/RouteSelectionDescriptor.aidl
index 02596a1..434ee7d 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/RouteSelectionDescriptor.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/RouteSelectionDescriptor.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable RouteSelectionDescriptor {
   byte precedence;
   android.hardware.radio.data.PdpProtocolType sessionType;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/SetupDataCallResult.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/SetupDataCallResult.aidl
index ff2459c..83f9db6 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/SetupDataCallResult.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/SetupDataCallResult.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable SetupDataCallResult {
   android.hardware.radio.data.DataCallFailCause cause;
   long suggestedRetryTime;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/SliceInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/SliceInfo.aidl
index 0dd8127..efe4816 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/SliceInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/SliceInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable SliceInfo {
   byte sliceServiceType;
   int sliceDifferentiator;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/SlicingConfig.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/SlicingConfig.aidl
index 54e2f12..b00febe 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/SlicingConfig.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/SlicingConfig.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable SlicingConfig {
   android.hardware.radio.data.UrspRule[] urspRules;
   android.hardware.radio.data.SliceInfo[] sliceInfo;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/TrafficDescriptor.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/TrafficDescriptor.aidl
index d5079c1..d7b0654 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/TrafficDescriptor.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/TrafficDescriptor.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable TrafficDescriptor {
   @nullable String dnn;
   @nullable android.hardware.radio.data.OsAppId osAppId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/UrspRule.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/UrspRule.aidl
index c0be054..7002fd1 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/UrspRule.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/1/android/hardware/radio/data/UrspRule.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.data;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable UrspRule {
   int precedence;
   android.hardware.radio.data.TrafficDescriptor[] trafficDescriptors;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/.hash b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/.hash
index c70c2c8..b972bab 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/.hash
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/.hash
@@ -1 +1,2 @@
 725d66fbe595788886858e33291c8a9048825f85
+5237ec5f500627b6b844b155e356e603157f9ba6
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaBroadcastSmsConfigInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaBroadcastSmsConfigInfo.aidl
index 54e8a7b..39e2be2 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaBroadcastSmsConfigInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaBroadcastSmsConfigInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CdmaBroadcastSmsConfigInfo {
   int serviceCategory;
   int language;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsAck.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsAck.aidl
index 0de1688..befdbde 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsAck.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsAck.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CdmaSmsAck {
   boolean errorClass;
   int smsCauseCode;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsAddress.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsAddress.aidl
index 4a55745..ab29c77 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsAddress.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsAddress.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CdmaSmsAddress {
   int digitMode;
   boolean isNumberModeDataNetwork;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsMessage.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsMessage.aidl
index fdb74fb..867596c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsMessage.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsMessage.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CdmaSmsMessage {
   int teleserviceId;
   boolean isServicePresent;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsSubaddress.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsSubaddress.aidl
index deb1102..d67fe8c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsSubaddress.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsSubaddress.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CdmaSmsSubaddress {
   int subaddressType;
   boolean odd;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsWriteArgs.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsWriteArgs.aidl
index 4969663..b0a7f98 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsWriteArgs.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/CdmaSmsWriteArgs.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CdmaSmsWriteArgs {
   int status;
   android.hardware.radio.messaging.CdmaSmsMessage message;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/GsmBroadcastSmsConfigInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/GsmBroadcastSmsConfigInfo.aidl
index 6cc7636..46604ca 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/GsmBroadcastSmsConfigInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/GsmBroadcastSmsConfigInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable GsmBroadcastSmsConfigInfo {
   int fromServiceId;
   int toServiceId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/GsmSmsMessage.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/GsmSmsMessage.aidl
index 2937d5c..4df7fd2 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/GsmSmsMessage.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/GsmSmsMessage.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable GsmSmsMessage {
   String smscPdu;
   String pdu;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/ImsSmsMessage.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/ImsSmsMessage.aidl
index 706bfdd..85f62b7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/ImsSmsMessage.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/ImsSmsMessage.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable ImsSmsMessage {
   android.hardware.radio.RadioTechnologyFamily tech;
   boolean retry;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/SendSmsResult.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/SendSmsResult.aidl
index 0fbec6f..32f7a5c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/SendSmsResult.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/SendSmsResult.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable SendSmsResult {
   int messageRef;
   String ackPDU;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/SmsAcknowledgeFailCause.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/SmsAcknowledgeFailCause.aidl
index b1f8ff8..019b185 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/SmsAcknowledgeFailCause.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/SmsAcknowledgeFailCause.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum SmsAcknowledgeFailCause {
   MEMORY_CAPACITY_EXCEEDED = 211,
   UNSPECIFIED_ERROR = 255,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/SmsWriteArgs.aidl b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/SmsWriteArgs.aidl
index 1748b62..489cc07 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/SmsWriteArgs.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.messaging/1/android/hardware/radio/messaging/SmsWriteArgs.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.messaging;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable SmsWriteArgs {
   int status;
   String pdu;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/1/.hash b/radio/aidl/aidl_api/android.hardware.radio.modem/1/.hash
index 18996c5..a6d3c50 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/1/.hash
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/1/.hash
@@ -1 +1,2 @@
 8883a1066be2bbc8c65a2db115b02e3e92bbfc98
+9dee2319b599d654955c05268c1eed6ca4373b58
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/ActivityStatsInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/ActivityStatsInfo.aidl
index 93940fd..7e22ee0 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/ActivityStatsInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/ActivityStatsInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable ActivityStatsInfo {
   int sleepModeTimeMs;
   int idleModeTimeMs;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl
index 798ec36..08ed9a5 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/ActivityStatsTechSpecificInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable ActivityStatsTechSpecificInfo {
   android.hardware.radio.AccessNetwork rat;
   int frequencyRange;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/DeviceStateType.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/DeviceStateType.aidl
index 0f0006d..4e8c6d7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/DeviceStateType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/DeviceStateType.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum DeviceStateType {
   POWER_SAVE_MODE = 0,
   CHARGING_STATE = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/HardwareConfig.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/HardwareConfig.aidl
index 7593ca7..3a0ec25 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/HardwareConfig.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/HardwareConfig.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable HardwareConfig {
   int type;
   String uuid;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/HardwareConfigModem.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/HardwareConfigModem.aidl
index bf70995..62bb160 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/HardwareConfigModem.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/HardwareConfigModem.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable HardwareConfigModem {
   int rilModel;
   android.hardware.radio.RadioTechnology rat;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/HardwareConfigSim.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/HardwareConfigSim.aidl
index 1b887c2..5810982 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/HardwareConfigSim.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/HardwareConfigSim.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable HardwareConfigSim {
   String modemUuid;
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/NvItem.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/NvItem.aidl
index bda4ab7..3e27643 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/NvItem.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/NvItem.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum NvItem {
   CDMA_MEID = 1,
   CDMA_MIN = 2,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/NvWriteItem.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/NvWriteItem.aidl
index 58e8498..17b7de0 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/NvWriteItem.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/NvWriteItem.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable NvWriteItem {
   android.hardware.radio.modem.NvItem itemId;
   String value;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/RadioCapability.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/RadioCapability.aidl
index 5aaf5a7..f2e2858 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/RadioCapability.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/RadioCapability.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable RadioCapability {
   int session;
   int phase;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/RadioState.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/RadioState.aidl
index 4bde770..57f2941 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/RadioState.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/RadioState.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum RadioState {
   OFF = 0,
   UNAVAILABLE = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/ResetNvType.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/ResetNvType.aidl
index 81f2254..e3b5796 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/ResetNvType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/1/android/hardware/radio/modem/ResetNvType.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.modem;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum ResetNvType {
   RELOAD = 0,
   ERASE = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/.hash b/radio/aidl/aidl_api/android.hardware.radio.network/1/.hash
index 747eca4..43dd434 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/.hash
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/.hash
@@ -1 +1,2 @@
 ffa236a8203511b871b2d141b0f7c6d37f746bb4
+57e8e923513d80a26102e450d335e89b4346be66
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/AccessTechnologySpecificInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/AccessTechnologySpecificInfo.aidl
index 4a4a120..28d8862 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/AccessTechnologySpecificInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/AccessTechnologySpecificInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 union AccessTechnologySpecificInfo {
   boolean noinit;
   android.hardware.radio.network.Cdma2000RegistrationInfo cdmaInfo;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/BarringInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/BarringInfo.aidl
index a96ef51..e105b39 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/BarringInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/BarringInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable BarringInfo {
   int serviceType;
   int barringType;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/BarringTypeSpecificInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/BarringTypeSpecificInfo.aidl
index c04cdb5..a813633 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/BarringTypeSpecificInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/BarringTypeSpecificInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable BarringTypeSpecificInfo {
   int factor;
   int timeSeconds;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/Cdma2000RegistrationInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/Cdma2000RegistrationInfo.aidl
index 7d9292d..74c4e29 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/Cdma2000RegistrationInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/Cdma2000RegistrationInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable Cdma2000RegistrationInfo {
   boolean cssSupported;
   int roamingIndicator;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CdmaRoamingType.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CdmaRoamingType.aidl
index 54c431b..24ec26b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CdmaRoamingType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CdmaRoamingType.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum CdmaRoamingType {
   HOME_NETWORK = 0,
   AFFILIATED_ROAM = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CdmaSignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CdmaSignalStrength.aidl
index b4aee1c..e2f97bf 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CdmaSignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CdmaSignalStrength.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CdmaSignalStrength {
   int dbm;
   int ecio;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellConnectionStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellConnectionStatus.aidl
index 066cb60..8986d71 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellConnectionStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellConnectionStatus.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum CellConnectionStatus {
   NONE = 0,
   PRIMARY_SERVING = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentity.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentity.aidl
index 1c68e8c..2ee92de 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentity.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentity.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 union CellIdentity {
   boolean noinit;
   android.hardware.radio.network.CellIdentityGsm gsm;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityCdma.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityCdma.aidl
index 8c1fdfa..d659a28 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityCdma.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityCdma.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CellIdentityCdma {
   int networkId;
   int systemId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityGsm.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityGsm.aidl
index 2e384e9..d3193be 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityGsm.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityGsm.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CellIdentityGsm {
   String mcc;
   String mnc;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityLte.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityLte.aidl
index c83997e..2ae7b43 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityLte.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityLte.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CellIdentityLte {
   String mcc;
   String mnc;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityNr.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityNr.aidl
index 6bdfd99..b30af50 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityNr.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityNr.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CellIdentityNr {
   String mcc;
   String mnc;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityTdscdma.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityTdscdma.aidl
index 4100805..e99d147 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityTdscdma.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityTdscdma.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CellIdentityTdscdma {
   String mcc;
   String mnc;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityWcdma.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityWcdma.aidl
index 907f30d..12001fc 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityWcdma.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellIdentityWcdma.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CellIdentityWcdma {
   String mcc;
   String mnc;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfo.aidl
index 38e0a44..467c6b7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CellInfo {
   boolean registered;
   android.hardware.radio.network.CellConnectionStatus connectionStatus;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoCdma.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoCdma.aidl
index d171a4b..e3bf46b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoCdma.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoCdma.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CellInfoCdma {
   android.hardware.radio.network.CellIdentityCdma cellIdentityCdma;
   android.hardware.radio.network.CdmaSignalStrength signalStrengthCdma;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoGsm.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoGsm.aidl
index 491b686..84dcd07 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoGsm.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoGsm.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CellInfoGsm {
   android.hardware.radio.network.CellIdentityGsm cellIdentityGsm;
   android.hardware.radio.network.GsmSignalStrength signalStrengthGsm;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoLte.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoLte.aidl
index 67c5a18..221340b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoLte.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoLte.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CellInfoLte {
   android.hardware.radio.network.CellIdentityLte cellIdentityLte;
   android.hardware.radio.network.LteSignalStrength signalStrengthLte;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoNr.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoNr.aidl
index a094600..b392c1d 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoNr.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoNr.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CellInfoNr {
   android.hardware.radio.network.CellIdentityNr cellIdentityNr;
   android.hardware.radio.network.NrSignalStrength signalStrengthNr;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoRatSpecificInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoRatSpecificInfo.aidl
index 4e0719c..4ab0640 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoRatSpecificInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoRatSpecificInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 union CellInfoRatSpecificInfo {
   android.hardware.radio.network.CellInfoGsm gsm;
   android.hardware.radio.network.CellInfoWcdma wcdma;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoTdscdma.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoTdscdma.aidl
index d4e0874..138b35c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoTdscdma.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoTdscdma.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CellInfoTdscdma {
   android.hardware.radio.network.CellIdentityTdscdma cellIdentityTdscdma;
   android.hardware.radio.network.TdscdmaSignalStrength signalStrengthTdscdma;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoWcdma.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoWcdma.aidl
index da19e37..cf7b135 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoWcdma.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/CellInfoWcdma.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CellInfoWcdma {
   android.hardware.radio.network.CellIdentityWcdma cellIdentityWcdma;
   android.hardware.radio.network.WcdmaSignalStrength signalStrengthWcdma;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/ClosedSubscriberGroupInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/ClosedSubscriberGroupInfo.aidl
index 5c45d93..fe734c8 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/ClosedSubscriberGroupInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/ClosedSubscriberGroupInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable ClosedSubscriberGroupInfo {
   boolean csgIndication;
   String homeNodebName;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/Domain.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/Domain.aidl
index 712bbdb..209cf5e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/Domain.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/Domain.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum Domain {
   CS = 1,
   PS = 2,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/EutranBands.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/EutranBands.aidl
index 6c94d15..57fac3f 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/EutranBands.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/EutranBands.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum EutranBands {
   BAND_1 = 1,
   BAND_2 = 2,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/EutranRegistrationInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/EutranRegistrationInfo.aidl
index 098b57e..dfbf881 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/EutranRegistrationInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/EutranRegistrationInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable EutranRegistrationInfo {
   android.hardware.radio.network.LteVopsInfo lteVopsInfo;
   android.hardware.radio.network.NrIndicators nrIndicators;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/EvdoSignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/EvdoSignalStrength.aidl
index 7ec1635..7c56711 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/EvdoSignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/EvdoSignalStrength.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable EvdoSignalStrength {
   int dbm;
   int ecio;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/GeranBands.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/GeranBands.aidl
index 7cb0fd5..135935f 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/GeranBands.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/GeranBands.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum GeranBands {
   BAND_T380 = 1,
   BAND_T410 = 2,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/GsmSignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/GsmSignalStrength.aidl
index 4142ae7..2b53b39 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/GsmSignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/GsmSignalStrength.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable GsmSignalStrength {
   int signalStrength;
   int bitErrorRate;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/IndicationFilter.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/IndicationFilter.aidl
index f79ff2a..d9ed68e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/IndicationFilter.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/IndicationFilter.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum IndicationFilter {
   NONE = 0,
   ALL = -1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/LceDataInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/LceDataInfo.aidl
index 1876465..27b16c1 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/LceDataInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/LceDataInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable LceDataInfo {
   int lastHopCapacityKbps;
   byte confidenceLevel;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/LinkCapacityEstimate.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/LinkCapacityEstimate.aidl
index c34f177..5707b8e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/LinkCapacityEstimate.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/LinkCapacityEstimate.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable LinkCapacityEstimate {
   int downlinkCapacityKbps;
   int uplinkCapacityKbps;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/LteSignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/LteSignalStrength.aidl
index c7b41f1..b5b8579 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/LteSignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/LteSignalStrength.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable LteSignalStrength {
   int signalStrength;
   int rsrp;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/LteVopsInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/LteVopsInfo.aidl
index 9f20b10..6d8dd4e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/LteVopsInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/LteVopsInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable LteVopsInfo {
   boolean isVopsSupported;
   boolean isEmcBearerSupported;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NetworkScanRequest.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NetworkScanRequest.aidl
index 1e657e5..6039740 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NetworkScanRequest.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NetworkScanRequest.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable NetworkScanRequest {
   int type;
   int interval;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NetworkScanResult.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NetworkScanResult.aidl
index 3dc3940..4e392d0 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NetworkScanResult.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NetworkScanResult.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable NetworkScanResult {
   int status;
   android.hardware.radio.RadioError error;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NgranBands.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NgranBands.aidl
index aa60cde..5904690 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NgranBands.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NgranBands.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum NgranBands {
   BAND_1 = 1,
   BAND_2 = 2,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NrDualConnectivityState.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NrDualConnectivityState.aidl
index 6ee526f..62c2a56 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NrDualConnectivityState.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NrDualConnectivityState.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@Backing(type="byte") @VintfStability
+@Backing(type="byte") @JavaDerive(toString=true) @VintfStability
 enum NrDualConnectivityState {
   ENABLE = 1,
   DISABLE = 2,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NrIndicators.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NrIndicators.aidl
index 54f9b8f..88429f6 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NrIndicators.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NrIndicators.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable NrIndicators {
   boolean isEndcAvailable;
   boolean isDcNrRestricted;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NrSignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NrSignalStrength.aidl
index 14b60a6..98bbe6b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NrSignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NrSignalStrength.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable NrSignalStrength {
   int ssRsrp;
   int ssRsrq;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NrVopsInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NrVopsInfo.aidl
index 7f58ee1..e5a0a70 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NrVopsInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/NrVopsInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable NrVopsInfo {
   byte vopsSupported;
   byte emcSupported;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/OperatorInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/OperatorInfo.aidl
index c3658d9..034150e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/OperatorInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/OperatorInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable OperatorInfo {
   String alphaLong;
   String alphaShort;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/PhoneRestrictedState.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/PhoneRestrictedState.aidl
index dff8be0..41555f9 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/PhoneRestrictedState.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/PhoneRestrictedState.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum PhoneRestrictedState {
   NONE = 0,
   CS_EMERGENCY = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/PhysicalChannelConfig.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/PhysicalChannelConfig.aidl
index 8db6bc4..928c6b7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/PhysicalChannelConfig.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/PhysicalChannelConfig.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable PhysicalChannelConfig {
   android.hardware.radio.network.CellConnectionStatus status;
   android.hardware.radio.RadioTechnology rat;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/PhysicalChannelConfigBand.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/PhysicalChannelConfigBand.aidl
index 50af816..efc64a6 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/PhysicalChannelConfigBand.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/PhysicalChannelConfigBand.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 union PhysicalChannelConfigBand {
   boolean noinit;
   android.hardware.radio.network.GeranBands geranBand;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RadioAccessSpecifier.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RadioAccessSpecifier.aidl
index b412f63..1566bb5 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RadioAccessSpecifier.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RadioAccessSpecifier.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable RadioAccessSpecifier {
   android.hardware.radio.AccessNetwork accessNetwork;
   android.hardware.radio.network.RadioAccessSpecifierBands bands;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RadioAccessSpecifierBands.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RadioAccessSpecifierBands.aidl
index d44a883..a6ac12a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RadioAccessSpecifierBands.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RadioAccessSpecifierBands.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 union RadioAccessSpecifierBands {
   boolean noinit;
   android.hardware.radio.network.GeranBands[] geranBands;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RadioBandMode.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RadioBandMode.aidl
index 7266fd5..e9a9f60 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RadioBandMode.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RadioBandMode.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum RadioBandMode {
   BAND_MODE_UNSPECIFIED = 0,
   BAND_MODE_EURO = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RegState.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RegState.aidl
index d10f413..e6e7999 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RegState.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RegState.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum RegState {
   NOT_REG_MT_NOT_SEARCHING_OP = 0,
   REG_HOME = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RegStateResult.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RegStateResult.aidl
index eff2216..f0a03ae 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RegStateResult.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RegStateResult.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable RegStateResult {
   android.hardware.radio.network.RegState regState;
   android.hardware.radio.RadioTechnology rat;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RegistrationFailCause.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RegistrationFailCause.aidl
index 75fcdf4..e2cd44c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RegistrationFailCause.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/RegistrationFailCause.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum RegistrationFailCause {
   NONE = 0,
   IMSI_UNKNOWN_IN_HLR = 2,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/SignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/SignalStrength.aidl
index 7187116..1c50190 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/SignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/SignalStrength.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable SignalStrength {
   android.hardware.radio.network.GsmSignalStrength gsm;
   android.hardware.radio.network.CdmaSignalStrength cdma;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/SignalThresholdInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/SignalThresholdInfo.aidl
index 159d9c1..040932c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/SignalThresholdInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/SignalThresholdInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable SignalThresholdInfo {
   int signalMeasurement;
   int hysteresisMs;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/SuppSvcNotification.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/SuppSvcNotification.aidl
index 541754e..b62c71b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/SuppSvcNotification.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/SuppSvcNotification.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable SuppSvcNotification {
   boolean isMT;
   int code;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/TdscdmaSignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/TdscdmaSignalStrength.aidl
index a00345f..d74c950 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/TdscdmaSignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/TdscdmaSignalStrength.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable TdscdmaSignalStrength {
   int signalStrength;
   int bitErrorRate;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/UsageSetting.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/UsageSetting.aidl
index 7fdf831..3ca16b5 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/UsageSetting.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/UsageSetting.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum UsageSetting {
   VOICE_CENTRIC = 1,
   DATA_CENTRIC = 2,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/UtranBands.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/UtranBands.aidl
index 87d5b85..8be3da2 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/UtranBands.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/UtranBands.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum UtranBands {
   BAND_1 = 1,
   BAND_2 = 2,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/WcdmaSignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/WcdmaSignalStrength.aidl
index 678ace9..9112527 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/WcdmaSignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/1/android/hardware/radio/network/WcdmaSignalStrength.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.network;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable WcdmaSignalStrength {
   int signalStrength;
   int bitErrorRate;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/.hash b/radio/aidl/aidl_api/android.hardware.radio.sim/1/.hash
index 8d5d79a..77252d7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/.hash
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/.hash
@@ -1 +1,2 @@
 6c75ba42a812cccc0f73ada23e5b2581dfedcacb
+01cea196fdf8f5e41fda8dc41125f1cc2b96f757
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/AppStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/AppStatus.aidl
index 89d8f9a..8a41fb9 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/AppStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/AppStatus.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable AppStatus {
   int appType;
   int appState;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/CardPowerState.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/CardPowerState.aidl
index c0026ba..05bc13a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/CardPowerState.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/CardPowerState.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum CardPowerState {
   POWER_DOWN = 0,
   POWER_UP = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/CardStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/CardStatus.aidl
index cf37a0d..9000d43 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/CardStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/CardStatus.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CardStatus {
   int cardState;
   android.hardware.radio.sim.PinState universalPinState;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/Carrier.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/Carrier.aidl
index c7fced1..cc56888 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/Carrier.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/Carrier.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable Carrier {
   String mcc;
   String mnc;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/CarrierRestrictions.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/CarrierRestrictions.aidl
index 85cf86e..944f1ca 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/CarrierRestrictions.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/CarrierRestrictions.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CarrierRestrictions {
   android.hardware.radio.sim.Carrier[] allowedCarriers;
   android.hardware.radio.sim.Carrier[] excludedCarriers;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/CdmaSubscriptionSource.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/CdmaSubscriptionSource.aidl
index 50e768c..13469f3 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/CdmaSubscriptionSource.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/CdmaSubscriptionSource.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum CdmaSubscriptionSource {
   RUIM_SIM = 0,
   NV = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/IccIo.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/IccIo.aidl
index 3e4dcf6..5a312dc 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/IccIo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/IccIo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable IccIo {
   int command;
   int fileId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/IccIoResult.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/IccIoResult.aidl
index 58e43eb..6c6bde2 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/IccIoResult.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/IccIoResult.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable IccIoResult {
   int sw1;
   int sw2;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/ImsiEncryptionInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/ImsiEncryptionInfo.aidl
index 087f399..05e71cd 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/ImsiEncryptionInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/ImsiEncryptionInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable ImsiEncryptionInfo {
   String mcc;
   String mnc;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PbReceivedStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PbReceivedStatus.aidl
index 61babac..5e96fc6 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PbReceivedStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PbReceivedStatus.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@Backing(type="byte") @VintfStability
+@Backing(type="byte") @JavaDerive(toString=true) @VintfStability
 enum PbReceivedStatus {
   PB_RECEIVED_OK = 1,
   PB_RECEIVED_ERROR = 2,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PersoSubstate.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PersoSubstate.aidl
index a09d781..e33769e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PersoSubstate.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PersoSubstate.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum PersoSubstate {
   UNKNOWN = 0,
   IN_PROGRESS = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PhonebookCapacity.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PhonebookCapacity.aidl
index c1fa765..7531c96 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PhonebookCapacity.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PhonebookCapacity.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable PhonebookCapacity {
   int maxAdnRecords;
   int usedAdnRecords;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PhonebookRecordInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PhonebookRecordInfo.aidl
index 36bc920..2e96a4b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PhonebookRecordInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PhonebookRecordInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable PhonebookRecordInfo {
   int recordId;
   String name;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PinState.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PinState.aidl
index c78b92c..5cdc6d1 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PinState.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/PinState.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum PinState {
   UNKNOWN = 0,
   ENABLED_NOT_VERIFIED = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/SelectUiccSub.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/SelectUiccSub.aidl
index 4842fbe..02121e6 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/SelectUiccSub.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/SelectUiccSub.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable SelectUiccSub {
   int slot;
   int appIndex;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/SimApdu.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/SimApdu.aidl
index d8e1dde..2201345 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/SimApdu.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/SimApdu.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable SimApdu {
   int sessionId;
   int cla;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl
index 6fd89d5..4ded3e9 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/SimLockMultiSimPolicy.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum SimLockMultiSimPolicy {
   NO_MULTISIM_POLICY = 0,
   ONE_VALID_SIM_MUST_BE_PRESENT = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/SimRefreshResult.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/SimRefreshResult.aidl
index dd3c1f2..69bf476 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/SimRefreshResult.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/1/android/hardware/radio/sim/SimRefreshResult.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.sim;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable SimRefreshResult {
   int type;
   int efId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/.hash b/radio/aidl/aidl_api/android.hardware.radio.voice/1/.hash
index 5434224..fd705af 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/.hash
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/.hash
@@ -1 +1,2 @@
 bc19c55b40e9ed285c21b6c1aaa66fe855bf031b
+e9ffc70247a89e6c1e526c6334c37da46f33ebea
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/AudioQuality.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/AudioQuality.aidl
index 89bd2dc..15669ac 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/AudioQuality.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/AudioQuality.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum AudioQuality {
   UNSPECIFIED = 0,
   AMR = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/Call.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/Call.aidl
index 7f44531..10d2ee7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/Call.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/Call.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable Call {
   int state;
   int index;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CallForwardInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CallForwardInfo.aidl
index 7ef9e46..8e7aaab 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CallForwardInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CallForwardInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CallForwardInfo {
   int status;
   int reason;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaCallWaiting.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaCallWaiting.aidl
index 9edf1e7..310f9a0 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaCallWaiting.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaCallWaiting.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CdmaCallWaiting {
   String number;
   int numberPresentation;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaDisplayInfoRecord.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaDisplayInfoRecord.aidl
index b373aa5..b6b562c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaDisplayInfoRecord.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaDisplayInfoRecord.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CdmaDisplayInfoRecord {
   String alphaBuf;
   const int CDMA_ALPHA_INFO_BUFFER_LENGTH = 64;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaInformationRecord.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaInformationRecord.aidl
index cc4d3fa..24ae775 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaInformationRecord.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaInformationRecord.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CdmaInformationRecord {
   int name;
   android.hardware.radio.voice.CdmaDisplayInfoRecord[] display;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaLineControlInfoRecord.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaLineControlInfoRecord.aidl
index d7f6cd4..e34b393 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaLineControlInfoRecord.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaLineControlInfoRecord.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CdmaLineControlInfoRecord {
   byte lineCtrlPolarityIncluded;
   byte lineCtrlToggle;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaNumberInfoRecord.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaNumberInfoRecord.aidl
index 26a7df5..aeb0347 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaNumberInfoRecord.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaNumberInfoRecord.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CdmaNumberInfoRecord {
   String number;
   byte numberType;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaOtaProvisionStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaOtaProvisionStatus.aidl
index 5ea4e50..7877fda 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaOtaProvisionStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaOtaProvisionStatus.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum CdmaOtaProvisionStatus {
   SPL_UNLOCKED = 0,
   SPC_RETRIES_EXCEEDED = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaRedirectingNumberInfoRecord.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaRedirectingNumberInfoRecord.aidl
index f0f2b04..b61b91b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaRedirectingNumberInfoRecord.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaRedirectingNumberInfoRecord.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CdmaRedirectingNumberInfoRecord {
   android.hardware.radio.voice.CdmaNumberInfoRecord redirectingNumber;
   int redirectingReason;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaSignalInfoRecord.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaSignalInfoRecord.aidl
index 2ebb396..6c7b264 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaSignalInfoRecord.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaSignalInfoRecord.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CdmaSignalInfoRecord {
   boolean isPresent;
   byte signalType;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaT53AudioControlInfoRecord.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaT53AudioControlInfoRecord.aidl
index 33e2c2b..438231c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaT53AudioControlInfoRecord.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaT53AudioControlInfoRecord.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CdmaT53AudioControlInfoRecord {
   byte upLink;
   byte downLink;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaT53ClirInfoRecord.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaT53ClirInfoRecord.aidl
index 457fd18..1b254f5 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaT53ClirInfoRecord.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CdmaT53ClirInfoRecord.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CdmaT53ClirInfoRecord {
   byte cause;
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CfData.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CfData.aidl
index 744e7ae..7e799c7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CfData.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/CfData.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable CfData {
   android.hardware.radio.voice.CallForwardInfo[] cfInfo;
   const int NUM_SERVICE_CLASSES = 7;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/ClipStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/ClipStatus.aidl
index dafc2b9..3fbb0d8 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/ClipStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/ClipStatus.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum ClipStatus {
   CLIP_PROVISIONED = 0,
   CLIP_UNPROVISIONED = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/Dial.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/Dial.aidl
index c9a02a9..2b2e759 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/Dial.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/Dial.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable Dial {
   String address;
   int clir;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/EmergencyCallRouting.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/EmergencyCallRouting.aidl
index b31a661..07f011d 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/EmergencyCallRouting.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/EmergencyCallRouting.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum EmergencyCallRouting {
   UNKNOWN = 0,
   EMERGENCY = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/EmergencyNumber.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/EmergencyNumber.aidl
index 39bcf1a..98df8cd 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/EmergencyNumber.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/EmergencyNumber.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable EmergencyNumber {
   String number;
   String mcc;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/EmergencyServiceCategory.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/EmergencyServiceCategory.aidl
index 34d3c40..042dd61 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/EmergencyServiceCategory.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/EmergencyServiceCategory.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum EmergencyServiceCategory {
   UNSPECIFIED = 0,
   POLICE = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/LastCallFailCause.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/LastCallFailCause.aidl
index 3e17840..1740134 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/LastCallFailCause.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/LastCallFailCause.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum LastCallFailCause {
   UNOBTAINABLE_NUMBER = 1,
   NO_ROUTE_TO_DESTINATION = 3,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/LastCallFailCauseInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/LastCallFailCauseInfo.aidl
index af75a40..221acf7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/LastCallFailCauseInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/LastCallFailCauseInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable LastCallFailCauseInfo {
   android.hardware.radio.voice.LastCallFailCause causeCode;
   String vendorCause;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/SrvccState.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/SrvccState.aidl
index 8e7e9fb..864374b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/SrvccState.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/SrvccState.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum SrvccState {
   HANDOVER_STARTED = 0,
   HANDOVER_COMPLETED = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/SsInfoData.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/SsInfoData.aidl
index 9517847..f18b404 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/SsInfoData.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/SsInfoData.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable SsInfoData {
   int[] ssInfo;
   const int SS_INFO_MAX = 4;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/StkCcUnsolSsResult.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/StkCcUnsolSsResult.aidl
index 71ef7a7..50bb1fd 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/StkCcUnsolSsResult.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/StkCcUnsolSsResult.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable StkCcUnsolSsResult {
   int serviceType;
   int requestType;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/TtyMode.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/TtyMode.aidl
index bb0a9f1..77417e8 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/TtyMode.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/TtyMode.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum TtyMode {
   OFF = 0,
   FULL = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/UssdModeType.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/UssdModeType.aidl
index 9a9d723..ad243d2 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/UssdModeType.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/UssdModeType.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@Backing(type="int") @VintfStability
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
 enum UssdModeType {
   NOTIFY = 0,
   REQUEST = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/UusInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/UusInfo.aidl
index 0198de9..9313760 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/UusInfo.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.voice/1/android/hardware/radio/voice/UusInfo.aidl
@@ -32,7 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.radio.voice;
-@VintfStability
+@JavaDerive(toString=true) @VintfStability
 parcelable UusInfo {
   int uusType;
   int uusDcs;
diff --git a/radio/aidl/android/hardware/radio/messaging/GsmSmsMessage.aidl b/radio/aidl/android/hardware/radio/messaging/GsmSmsMessage.aidl
index ee62d95..b256c9a 100644
--- a/radio/aidl/android/hardware/radio/messaging/GsmSmsMessage.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/GsmSmsMessage.aidl
@@ -27,6 +27,7 @@
     /**
      * SMS in PDU format as an ASCII hex string less the SMSC address.
      * TP-Layer-Length is be "strlen(pdu)/2
+     * TP - MessageRef field of pdu must not be modified by modem
      */
     String pdu;
 }
diff --git a/radio/aidl/vts/radio_network_response.cpp b/radio/aidl/vts/radio_network_response.cpp
index 666d617..2292c54 100644
--- a/radio/aidl/vts/radio_network_response.cpp
+++ b/radio/aidl/vts/radio_network_response.cpp
@@ -109,8 +109,9 @@
 }
 
 ndk::ScopedAStatus RadioNetworkResponse::getSystemSelectionChannelsResponse(
-        const RadioResponseInfo& info, const std::vector<RadioAccessSpecifier>& /*specifier*/) {
+        const RadioResponseInfo& info, const std::vector<RadioAccessSpecifier>& specifiers) {
     rspInfo = info;
+    this->specifiers = specifiers;
     parent_network.notify(info.serial);
     return ndk::ScopedAStatus::ok();
 }
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index 0bae374..c83571e 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -769,6 +769,16 @@
  */
 TEST_P(RadioNetworkTest, setSystemSelectionChannels) {
     serial = GetRandomSerialNumber();
+    ndk::ScopedAStatus res = radio_network->getSystemSelectionChannels(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+    if (radioRsp_network->specifiers.size() == 0) {
+        // TODO (b/189255895): Throw an error once getSystemSelectionChannels is functional.
+        ALOGI("Skipped the test due to empty system selection channels.");
+        GTEST_SKIP();
+    }
+    std::vector<RadioAccessSpecifier> originalSpecifiers = radioRsp_network->specifiers;
 
     RadioAccessSpecifierBands bandP900 =
             RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
@@ -781,8 +791,8 @@
     RadioAccessSpecifier specifier850 = {
             .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
 
-    ndk::ScopedAStatus res =
-            radio_network->setSystemSelectionChannels(serial, true, {specifierP900, specifier850});
+    serial = GetRandomSerialNumber();
+    res = radio_network->setSystemSelectionChannels(serial, true, {specifierP900, specifier850});
     ASSERT_OK(res);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
@@ -795,8 +805,8 @@
 
     if (radioRsp_network->rspInfo.error == RadioError::NONE) {
         serial = GetRandomSerialNumber();
-        ndk::ScopedAStatus res = radio_network->setSystemSelectionChannels(
-                serial, false, {specifierP900, specifier850});
+        res = radio_network->setSystemSelectionChannels(serial, false,
+                                                        {specifierP900, specifier850});
         ASSERT_OK(res);
         EXPECT_EQ(std::cv_status::no_timeout, wait());
         EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
@@ -805,6 +815,12 @@
               toString(radioRsp_network->rspInfo.error).c_str());
         EXPECT_EQ(RadioError::NONE, radioRsp_network->rspInfo.error);
     }
+
+    serial = GetRandomSerialNumber();
+    res = radio_network->setSystemSelectionChannels(serial, true, originalSpecifiers);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
 }
 
 /*
diff --git a/radio/aidl/vts/radio_network_utils.h b/radio/aidl/vts/radio_network_utils.h
index 29ba2f2..29f20e8 100644
--- a/radio/aidl/vts/radio_network_utils.h
+++ b/radio/aidl/vts/radio_network_utils.h
@@ -45,6 +45,7 @@
     CellIdentity barringCellIdentity;
     std::vector<BarringInfo> barringInfoList;
     UsageSetting usageSetting;
+    std::vector<RadioAccessSpecifier> specifiers;
 
     virtual ndk::ScopedAStatus acknowledgeRequest(int32_t serial) override;
 
diff --git a/rebootescrow/aidl/Android.bp b/rebootescrow/aidl/Android.bp
index c764f86..39aaa07 100644
--- a/rebootescrow/aidl/Android.bp
+++ b/rebootescrow/aidl/Android.bp
@@ -18,11 +18,6 @@
         java: {
             platform_apis: true,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions: ["1"],
 }
diff --git a/security/OWNERS b/security/OWNERS
index 54d820a..f061cd6 100644
--- a/security/OWNERS
+++ b/security/OWNERS
@@ -1,5 +1,7 @@
+# Please assign all bugs related to /hardware/interfaces/security to the team alias,
+# android-hardware-security@google.com.  This will get them auto-assigned to the on-call triage
+# engineer, ensuring quickest response.
 drysdale@google.com
 jbires@google.com
-jdanis@google.com
 seleneh@google.com
 swillden@google.com
diff --git a/security/dice/aidl/Android.bp b/security/dice/aidl/Android.bp
index 97781b3..5625d70 100644
--- a/security/dice/aidl/Android.bp
+++ b/security/dice/aidl/Android.bp
@@ -34,9 +34,6 @@
             platform_apis: false,
         },
         ndk: {
-            vndk: {
-                enabled: true,
-            },
             apps_enabled: false,
             apex_available: [
                 "//apex_available:platform",
diff --git a/security/keymint/RKP_CHANGELOG.md b/security/keymint/RKP_CHANGELOG.md
new file mode 100644
index 0000000..67d68d4
--- /dev/null
+++ b/security/keymint/RKP_CHANGELOG.md
@@ -0,0 +1,18 @@
+# Remote Provisioning Changelog
+
+This document provides an exact description of which changes have occurred in the
+`IRemotelyProvisionedComponent` HAL interface in each Android release.
+
+## Releases
+* **Android S (12):** IRemotelyProvisionedComponent v1
+* **Android T (13):** IRemotelyProvisionedComponent v2
+
+## IRemotelyProvisionedComponent 1 -> 2
+* DeviceInfo
+ * Most entries are no longer optional.
+ * `att_id_state` is now `fused`. `fused` is used to indicate if SecureBoot is enabled.
+ * `version` is now `2`.
+ * `board` has been removed.
+ * `device` has been added.
+* RpcHardwareInfo
+ * `uniqueId` String added as a field in order to differentiate IRPC instances on device.
\ No newline at end of file
diff --git a/security/keymint/RKP_README.md b/security/keymint/RKP_README.md
new file mode 100644
index 0000000..89a2598
--- /dev/null
+++ b/security/keymint/RKP_README.md
@@ -0,0 +1,374 @@
+# Remote Provisioning HAL
+
+## Objective
+
+Design a HAL to support over-the-air provisioning of certificates for asymmetric
+keys. The HAL must interact effectively with Keystore (and other daemons) and
+protect device privacy and security.
+
+Note that this API is designed for KeyMint, but with the intention that it
+should be usable for other HALs that require certificate provisioning.
+Throughout this document we'll refer to the Keystore and KeyMint (formerly
+called Keymaster) components, but only for concreteness and convenience; those
+labels could be replaced with the names of any system and secure area
+components, respectively, that need certificates provisioned.
+
+## Key design decisions
+
+### General approach
+
+To more securely and reliably get keys and certificates to Android devices, we
+need to create a system where no party outside of the device's secure components
+is responsible for managing private keys. The strategy we've chosen is to
+deliver certificates over the air, using an asymmetric key pair created
+on-device in the factory as a root of trust to create an authenticated, secure
+channel. In this document we refer to this device-unique asymmetric key pair as
+Device Key (DK), its public half DK\_pub, its private half DK\_priv and a Device
+Key Certificate containing DK\_pub is denoted DKC.
+
+In order for the provisioning service to use DK (or a key authenticated by DK),
+it must know whether a given DK\_pub is known and trusted. To prove trust, we
+ask device OEMs to use one of two mechanisms:
+
+1.  (Preferred, recommended) The device OEM extracts DK\_pub from each device it
+    manufactures and uploads the public keys to a backend server.
+
+1.  The device OEM signs the DK\_pub to produce DKC and stores it on the device.
+    This has the advantage that they don't need to upload a DK\_pub for every
+    device immediately, but the disadvantage that they have to manage their
+    private signing keys, which means they have to have HSMs, configure and
+    secure them correctly, etc. Some backend providers may also require that the
+    OEM passes a factory security audit, and additionally promises to upload the
+    keys eventually as well.
+
+Note that in the full elaboration of this plan, DK\_pub is not the key used to
+establish a secure channel. Instead, DK\_pub is just the first public key in a
+chain of public keys which ends with the KeyMint public key, KM\_pub. All keys
+in the chain are device-unique and are joined in a certificate chain called the
+_Boot Certificate Chain_ (BCC), because in phases 2 and 3 of the remote
+provisioning project it is a chain of certificates corresponding to boot phases.
+We speak of the BCC even for phase 1, though in phase 1 it contains only a
+single self-signed DKC. This is described in more depth in the Phases section
+below.
+
+The BCC is authenticated by DK\_pub. To authenticate DK\_pub, we may have
+additional DKCs, from the SoC vendor, the device OEM, or both. Those are not
+part of the BCC but included as optional fields in the certificate request
+structure.
+
+The format of the the DK and BCC is specified within [Open Profile for DICE]
+(https://pigweed.googlesource.com/open-dice/+/HEAD/docs/specification.md).  To
+map phrases within this document to their equivalent terminology in the DICE
+specification, read the terms as follows: the DK corresponds to the UDS-derived
+key pair, DKC corresponds to the UDS certificate, and the BCC entries between
+DK\_pub and KM\_pub correspond to a chain of CDI certificates.
+
+Note: In addition to allowing 32 byte hash values for fields in the BCC payload,
+this spec additionally constrains some of the choices allowed in open-DICE.
+Specifically, these include which entries are required and which are optional in
+the BCC payload, and which algorithms are acceptable for use.
+
+### Phases
+
+RKP will be deployed in three phases, in terms of managing the root of trust
+binding between the device and the backend. To briefly describe them:
+
+* Phase 1: In phase 1 there is only one entry in the BCC; DK_pub and KM_pub are
+  the same key and the certificate is self-signed.
+* Phase 2: This is identical to phase 1, except it leverages the hardware root
+  of trust process described by DICE. Instead of trust being rooted in the TEE,
+  it is now rooted in the ROM by key material blown into fuses which are only
+  accessible to the ROM code.
+* Phase 3: This is identical to Phase 2, except the SoC vendor also does the
+  public key extraction or certification in their facilities, along with the OEM
+  doing it in the factory. This tightens up the "supply chain" and aims to make
+  key upload management more secure.
+
+### Privacy considerations
+
+Because DK and the DKCs are unique, immutable, unspoofable hardware-bound
+identifiers for the device, we must limit access to them to the absolute minimum
+possible. We do this in two ways:
+
+1.  We require KeyMint (which knows the BCC and either knows or at least has the
+ability to use KM\_priv) to refuse to ever divulge the BCC or additional
+signatures in plaintext. Instead, KeyMint requires the caller to provide an
+_Endpoint Encryption Key_ (EEK), with which it will encrypt the data before
+returning it. When provisioning production keys, the EEK must be signed by an
+approved authority whose public key is embedded in KeyMint. When certifying test
+keys, KeyMint will accept any EEK without checking the signature, but will
+encrypt and return a test BCC, rather than the real one.  The result is that
+only an entity in possession of an Trusted EEK (TEEK) private key can discover
+the plaintext of the production BCC.
+1.  Having thus limited access to the public keys to the trusted party only, we
+need to prevent the entity from abusing this unique device identifier.  The
+approach and mechanisms for doing that are beyond the scope of this document
+(they must be addressed in the server design), but generally involve taking care
+to ensure that we do not create any links between user IDs, IP addresses or
+issued certificates and the device pubkey.
+
+Although the details of the mechanisms for preventing the entity from abusing
+the BCC are, as stated, beyond the scope of this document, there is a subtle
+design decision here made specifically to enable abuse prevention. Specifically
+the `CertificateRequest` message sent to the server is (in
+[CDDL](https://tools.ietf.org/html/rfc8610)):
+
+```
+cddl
+CertificateRequest = [
+    DeviceInfo,
+    challenge : bstr,
+    ProtectedData,
+    MacedKeysToSign
+]
+```
+
+The public keys to be attested by the server are in `MacedKeysToSign`, which is
+a COSE\_Mac0 structure, MACed with a key that is found in `ProtectedData`. The
+MAC key is signed by DK\_pub.
+
+This structure allows the backend component that has access to EEK\_priv to
+decrypt `ProtectedData`, validate that the request is from an authorized device,
+check that the request is fresh and verify and extract the MAC key. That backend
+component never sees any data related to the keys to be signed, but can provide
+the MAC key to another backend component that can verify `MacedKeysToSign` and
+proceed to generate the certificates.
+
+In this way, we can partition the provisioning server into one component that
+knows the device identity, as represented by DK\_pub, but never sees the keys to
+be certified or certificates generated, and another component that sees the keys
+to be certified and certificates generated but does not know the device
+identity.
+
+### Key and cryptographic message formatting
+
+For simplicity of generation and parsing, compactness of wire representation,
+and flexibility and standardization, we've settled on using the CBOR Object
+Signing and Encryption (COSE) standard, defined in [RFC
+8152](https://tools.ietf.org/html/rfc8152). COSE provides compact and reasonably
+simple, yet easily-extensible, wire formats for:
+
+*   Keys,
+*   MACed messages,
+*   Signed messages, and
+*   Encrypted messages
+
+COSE enables easy layering of these message formats, such as using a COSE\_Sign
+structure to contain a COSE\_Key with a public key in it. We call this a
+"certificate".
+
+Due to the complexity of the standard, we'll spell out the COSE structures
+completely in this document and in the HAL and other documentation, so that
+although implementors will need to understand CBOR and the CBOR Data Definition
+Language ([CDDL, defined in RFC 8610](https://tools.ietf.org/html/rfc8610)),
+they shouldn't need to understand COSE.
+
+Note, however, that the certificate chains returned from the provisioning server
+are standard X.509 certificates.
+
+### Algorithm choices
+
+This document uses:
+
+*   ECDSA P-256 for attestation signing keys;
+*   Remote provisioning protocol signing keys:
+  *  Ed25519 / P-256
+*   ECDH keys:
+  *  X25519 / P-256
+*   AES-GCM for all encryption;
+*   SHA-256 for all message digesting;
+*   HMAC-SHA-256 for all MACing; and
+*   HKDF-SHA-256 for all key derivation.
+
+We believe that Curve25519 offers the best tradeoff in terms of security,
+efficiency and global trustworthiness, and that it is now sufficiently
+widely-used and widely-implemented to make it a practical choice.
+
+However, since Secure Elements (SE) do not currently offer support for curve
+25519, we are allowing implementations to instead make use of EC P-256 for
+signing and ECDH. To put it simply, the device unique key pair will be a P-256
+key pair for ECDSA instead of Ed25519, and the ProtectedData COSE\_Encrypt
+message will have its payload encrypted with P-256 ECDH key exchange instead of
+X25519.
+
+The CDDL in the rest of the document will use the '/' operator to show areas
+where either curve 25519 or P-256 may be used. Since there is no easy way to
+bind choices across different CDDL groups, it is important that the implementor
+stays consistent in which type is chosen. E.g. taking ES256 as the choice for
+algorithm implies the implementor should also choose the P256 public key group
+further down in the COSE structure.
+
+### Testability
+
+It's critical that the remote provisioning implementation be testable, to
+minimize the probability that broken devices are sold to end users. To support
+testing, the remote provisioning HAL methods take a `testMode` argument. Keys
+created in test mode are tagged to indicate this. The provisioning server will
+check for the test mode tag and issue test certificates that do not chain back
+to a trusted public key. In test mode, any EEK will be accepted, enabling
+testing tools to use EEKs for which they have the private key so they can
+validate the content of certificate requests. The BCC included in the
+`CertificateRequest` must contain freshly-generated keys, not the real BCC keys.
+
+Keystore (or similar) will need to be able to handle both testMode keys and
+production keys and keep them distinct, generating test certificate requests
+when asked with a test EEK and production certificate requests when asked with a
+production EEK. Likewise, the interface used to instruct Keystore to create keys
+will need to be able to specify whether test or production keys are desired.
+
+## Design
+
+### Certificate provisioning flow
+
+TODO(jbires): Replace this with a `.png` containing a sequence diagram.  The
+provisioning flow looks something like this:
+
+Provisioner -> Keystore: Prepare N keys
+Keystore -> KeyMint: generateKeyPair
+KeyMint -> KeyMint: Generate  key pair
+KeyMint --> Keystore: key\_blob,pubkey
+Keystore -> Keystore: Store key\_blob,pubkey
+Provisioner -> Server: Get TEEK
+Server --> Provisioner: TEEK
+Provisioner -> Keystore: genCertReq(N, TEEK)
+Keystore -> KeyMint: genCertReq(pubkeys, TEEK)
+KeyMint -> KeyMint: Sign pubkeys & encrypt BCC
+KeyMint --> Keystore: signature, encrypted BCC
+Keystore -> Keystore: Construct cert\_request
+Keystore --> Provisioner: cert\_request
+Provisioner --> Server: cert\_request
+Server -> Server: Validate cert\_request
+Server -> Server: Generate certificates
+Server --> Provisioner: certificates
+Provisioner -> Keystore: certificates
+Keystore -> Keystore: Store certificates
+
+The actors in the above diagram are:
+
+*   **Server** is the backend certificate provisioning server. It has access to
+    the uploaded device public keys and is responsible for providing encryption
+    keys, decrypting and validating requests, and generating certificates in
+    response to requests.
+*   **Provisioner** is an application that is responsible for communicating with
+    the server and all of the system components that require key certificates
+    from the server. It also implements the policy that defines how many key
+    pairs each client should keep in their pool.
+*   **Keystore** is the [Android keystore
+    daemon](https://developer.android.com/training/articles/keystore) (or, more
+    generally, whatever system component manages communications with a
+    particular secure aread component).
+*   **KeyMint** is the secure area component that manages cryptographic keys and
+    performs attestations (or perhaps some other secure area component).
+
+### `BCC`
+
+The _Boot Certificate Chain_ (BCC) is the chain of certificates that contains
+DK\_pub as well as other often device-unique certificates. The BCC is
+represented as a COSE\_Key containing DK\_pub followed by an array of
+COSE\_Sign1 "certificates" containing public keys and optional additional
+information, ordered from root to leaf, with each certificate signing the next.
+The first certificate in the array is signed by DK\_pub, the last certificate
+has the KeyMint (or whatever) signing key's public key, KM\_pub. In phase 1
+there is only one entry; DK\_pub and KM\_pub are the same key and the
+certificate is self-signed.
+
+Each COSE\_Sign1 certificate is a CBOR Web Token (CWT) as described in [RFC
+8392](https://tools.ietf.org/html/rfc8392) with additional fields as described
+in the Open Profile for DICE. Of these additional fields, only the
+_subjectPublicKey_ and _keyUsage_ fields are expected to be present for the
+KM\_pub entry (that is, the last entry) in a BCC, but all fields required by the
+Open Profile for DICE are expected for other entries (each of which corresponds
+to a particular firmware component or boot stage). The CWT fields _iss_ and
+_sub_ identify the issuer and subject of the certificate and are consistent
+along the BCC entries; the issuer of a given entry matches the subject of the
+previous entry.
+
+The BCC is designed to be constructed using the Open Profile for DICE. In this
+case the DK key pair is derived from the UDS as described by that profile and
+all BCC entries before the leaf are CBOR CDI certificates chained from DK\_pub.
+The KM key pair is not part of the derived DICE chain. It is generated (not
+derived) by the KeyMint module, certified by the last key in the DICE chain, and
+added as the leaf BCC entry. The key usage field in this leaf certificate must
+indicate the key is not used to sign certificates. If a UDS certificate is
+available on the device it should appear in the certificate request as the leaf
+of a DKCertChain in AdditionalDKSignatures (see
+[CertificateRequest](#certificaterequest)).
+
+The Open Profile for DICE allows for an arbitrary configuration descriptor. For
+BCC entries, this configuration descriptor is a CBOR map with the following
+optional fields. If no fields are relevant, an empty map should be encoded.
+Additional implementation-specific fields may be added using key values not in
+the range \[-70000, -70999\] (these are reserved for future additions here).
+
+```
+| Name              | Key    | Value type | Meaning                           |
+| ----------------- | ------ | ---------- | ----------------------------------|
+| Component name    | -70002 | tstr       | Name of firmware component / boot |
+:                   :        :            : stage                             :
+| Component version | -70003 | int        | Version of firmware component /   |
+:                   :        :            : boot stage                        :
+| Resettable        | -70004 | null       | If present, key changes on factory|
+:                   :        :            : reset                             :
+```
+
+Please see
+[ProtectedData.aidl](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl)
+for a full CDDL definition of the BCC.
+
+### `CertificateRequest`
+
+The full CBOR message that will be sent to the server to request certificates
+is:
+
+```cddl
+CertificateRequest = [
+    DeviceInfo,
+    challenge : bstr,       // Provided by the server
+    ProtectedData,          // See ProtectedData.aidl
+    MacedKeysToSign         // See IRemotelyProvisionedComponent.aidl
+]
+
+DeviceInfo = [
+    VerifiedDeviceInfo,     // See DeviceInfo.aidl
+    UnverifiedDeviceInfo
+]
+
+// Unverified info is anything provided by the HLOS. Subject to change out of
+// step with the HAL.
+UnverifiedDeviceInfo = {
+    ? "fingerprint" : tstr,
+}
+
+```
+
+It will be the responsibility of Keystore and the Provisioner to construct the
+`CertificateRequest`. The HAL provides a method to generate the elements that
+need to be constructed on the secure side, which are the tag field of
+`MacedKeysToSign`, `VerifiedDeviceInfo`, and the ciphertext field of
+`ProtectedData`.
+
+### HAL
+
+The remote provisioning HAL provides a simple interface that can be implemented
+by multiple secure components that require remote provisioning. It would be
+slightly simpler to extend the KeyMint API, but that approach would only serve
+the needs of KeyMint, this is more general.
+
+NOTE the data structures defined in this HAL may look a little bloated and
+complex. This is because the COSE data structures are fully spelled-out; we
+could make it much more compact by not re-specifying the standardized elements
+and instead just referencing the standard, but it seems better to fully specify
+them. If the apparent complexity seems daunting, consider what the same would
+look like if traditional ASN.1 DER-based structures from X.509 and related
+standards were used and also fully elaborated.
+
+Please see the related HAL documentation directly in the source code at the
+following links:
+
+*   [IRemotelyProvisionedComponent
+    HAL](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl)
+*   [ProtectedData](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl)
+*   [MacedPublicKey](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl)
+*   [RpcHardwareInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl)
+*   [DeviceInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl)
+
diff --git a/security/keymint/aidl/Android.bp b/security/keymint/aidl/Android.bp
index a233087..96d44a7 100644
--- a/security/keymint/aidl/Android.bp
+++ b/security/keymint/aidl/Android.bp
@@ -22,9 +22,6 @@
             platform_apis: true,
         },
         ndk: {
-            vndk: {
-                enabled: true,
-            },
             apps_enabled: false,
         },
         rust: {
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index da02d54..2caa4d5 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -196,12 +196,12 @@
  * derive a key that is used to encrypt the private/secret key material.
  *
  * The root of trust consists of a bitstring that must be derived from the public key used by
- * Verified Boot to verify the signature on the boot image and from the lock state of the
- * device.  If the public key is changed to allow a different system image to be used or if the
- * lock state is changed, then all of the IKeyMintDevice-protected keys created by the previous
- * system state must be unusable, unless the previous state is restored.  The goal is to increase
- * the value of the software-enforced key access controls by making it impossible for an attacker-
- * installed operating system to use IKeyMintDevice keys.
+ * Verified Boot to verify the signature on the boot image, from the lock state and from the
+ * Verified Boot state of the device.  If the public key is changed to allow a different system
+ * image to be used or if the lock state is changed, then all of the IKeyMintDevice-protected keys
+ * created by the previous system state must be unusable, unless the previous state is restored.
+ * The goal is to increase the value of the software-enforced key access controls by making it
+ * impossible for an attacker-installed operating system to use IKeyMintDevice keys.
  *
  * == Version Binding ==
  *
@@ -336,6 +336,17 @@
      * Only Tag::KEY_SIZE is required to generate an 3DES key, and its value must be 168.  If
      * omitted, generateKey must return ErrorCode::UNSUPPORTED_KEY_SIZE.
      *
+     * == HMAC Keys ==
+     *
+     * Tag::KEY_SIZE must be provided to generate an HMAC key, and its value must be >= 64 and a
+     * multiple of 8.  All devices must support key sizes up to 512 bits, but StrongBox devices must
+     * not support key sizes larger than 512 bits.  If omitted or invalid, generateKey() must return
+     * ErrorCode::UNSUPPORTED_KEY_SIZE.
+     *
+     * Tag::MIN_MAC_LENGTH must be provided, and must be a multiple of 8 in the range 64 to 512
+     * bits (inclusive). If omitted, generateKey must return ErrorCode::MISSING_MIN_MAC_LENGTH; if
+     * invalid, generateKey must return ErrorCode::UNSUPPORTED_MIN_MAC_LENGTH.
+     *
      * @param keyParams Key generation parameters are defined as KeyMintDevice tag/value pairs,
      *        provided in params.  See above for detailed specifications of which tags are required
      *        for which types of keys.
@@ -661,19 +672,19 @@
      *   structure, because it cannot add the DigestInfo structure.  Instead, the IKeyMintDevice
      *   must construct 0x00 || 0x01 || PS || 0x00 || M, where M is the provided message and PS is a
      *   random padding string at least eight bytes in length.  The size of the RSA key has to be at
-     *   least 11 bytes larger than the message, otherwise begin() must return
+     *   least 11 bytes larger than the message, otherwise finish() must return
      *   ErrorCode::INVALID_INPUT_LENGTH.
      *
      * o PaddingMode::RSA_PKCS1_1_1_5_ENCRYPT padding does not require a digest.
      *
-     * o PaddingMode::RSA_PSS padding requires a digest, which must match one of the padding values
+     * o PaddingMode::RSA_PSS padding requires a digest, which must match one of the digest values
      *   in the key authorizations, and which may not be Digest::NONE.  begin() must return
      *   ErrorCode::INCOMPATIBLE_DIGEST if this is not the case.  In addition, the size of the RSA
-     *   key must be at least 2 + D bytes larger than the output size of the digest, where D is the
-     *   size of the digest, in bytes.  Otherwise begin() must return
-     *   ErrorCode::INCOMPATIBLE_DIGEST.  The salt size must be D.
+     *   key must be at least (D + S + 9) bits, where D is the size of the digest (in bits) and
+     *   S is the size of the salt (in bits).  The salt size S must equal D, so the RSA key must
+     *   be at least (2*D + 9) bits. Otherwise begin() must return ErrorCode::INCOMPATIBLE_DIGEST.
      *
-     * o PaddingMode::RSA_OAEP padding requires a digest, which must match one of the padding values
+     * o PaddingMode::RSA_OAEP padding requires a digest, which must match one of the digest values
      *   in the key authorizations, and which may not be Digest::NONE.  begin() must return
      *   ErrorCode::INCOMPATIBLE_DIGEST if this is not the case.  RSA_OAEP padding also requires an
      *   MGF1 digest, specified with Tag::RSA_OAEP_MGF_DIGEST, which must match one of the MGF1
@@ -683,9 +694,9 @@
      *
      * -- EC Keys --
      *
-     * Private key operations (KeyPurpose::SIGN) need authorization of digest and padding, which
-     * means that the key authorizations must contain the specified values.  If not, begin() must
-     * return ErrorCode::INCOMPATIBLE_DIGEST.
+     * Private key operations (KeyPurpose::SIGN) need authorization of digest, which means that the
+     * key authorizations must contain the specified values.  If not, begin() must return
+     * ErrorCode::INCOMPATIBLE_DIGEST.
      *
      * -- AES Keys --
      *
@@ -873,7 +884,7 @@
      * The returned data is an encoded COSE_Mac0 structure, denoted MacedRootOfTrust in the
      * following CDDL schema.  Note that K_mac is the shared HMAC key used for auth tokens, etc.:
      *
-     *     MacedRootOfTrust = [               ; COSE_Mac0 (untagged)
+     *     MacedRootOfTrust = #6.17 [         ; COSE_Mac0 (tagged)
      *         protected: bstr .cbor {
      *             1 : 5,                     ; Algorithm : HMAC-256
      *         },
@@ -891,7 +902,7 @@
      *         payload : bstr .cbor RootOfTrust,
      *     ]
      *
-     *     RootOfTrust = [
+     *     RootOfTrust = #6.40001 [           ; Tag 40001 indicates RoT v1.
      *         verifiedBootKey : bstr .size 32,
      *         deviceLocked : bool,
      *         verifiedBootState : &VerifiedBootState,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
index fd103ef..32e71a7 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
@@ -23,7 +23,7 @@
 @VintfStability
 @Backing(type="int")
 enum KeyPurpose {
-    /* Usable with RSA, 3DES and AES keys. */
+    /* Usable with 3DES and AES keys. */
     ENCRYPT = 0,
 
     /* Usable with RSA, 3DES and AES keys. */
@@ -32,7 +32,7 @@
     /* Usable with RSA, EC and HMAC keys. */
     SIGN = 2,
 
-    /* Usable with RSA, EC and HMAC keys. */
+    /* Usable with HMAC keys. */
     VERIFY = 3,
 
     /* 4 is reserved */
diff --git a/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl b/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
index e71a9c9..6ff4b29 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
@@ -26,7 +26,7 @@
 @VintfStability
 @Backing(type="int")
 enum PaddingMode {
-    NONE = 1, /* deprecated */
+    NONE = 1,
     RSA_OAEP = 2,
     RSA_PSS = 3,
     RSA_PKCS1_1_5_ENCRYPT = 4,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl b/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
index 6db58f2..8b3875b 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
@@ -100,15 +100,13 @@
      *     SignerName = tstr
      *
      *     DKCertChain = [
-     *         2* Certificate           // Root -> ... -> Leaf. "Root" is the vendor self-signed
+     *         2* X509Certificate       // Root -> ... -> Leaf. "Root" is the vendor self-signed
      *                                  // cert, "Leaf" contains DK_pub. There may also be
      *                                  // intermediate certificates between Root and Leaf.
      *     ]
      *
-     *     // Certificates may be either:
-     *     // 1. COSE_Sign1, with payload containing PubKeyEd25519 or PubKeyECDSA256
-     *     // 2. a bstr containing a DER-encoded X.509 certificate (RSA, NIST P-curve, or edDSA)
-     *     Certificate = COSE_Sign1 / bstr
+     *     // A bstr containing a DER-encoded X.509 certificate (RSA, NIST P-curve, or edDSA)
+     *     X509Certificate = bstr
      *
      *     // The SignedMac, which authenticates the MAC key that is used to authenticate the
      *     // keysToSign.
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index 42dfad5..871a1ac 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -186,10 +186,16 @@
      * Tag::RSA_OAEP_MGF_DIGEST specifies the MGF1 digest algorithms that may be used with RSA
      * encryption/decryption with OAEP padding.  Possible values are defined by the Digest enum.
      *
-     * This tag is repeatable for key generation/import.  RSA cipher operations with OAEP padding
-     * must specify an MGF1 digest in the params argument of begin(). If this tag is missing or the
-     * specified digest is not in the MGF1 digests associated with the key then begin operation must
-     * fail with ErrorCode::INCOMPATIBLE_MGF_DIGEST.
+     * This tag is repeatable for key generation/import.
+     *
+     * If the caller specifies an MGF1 digest in the params argument of begin(), that digest must be
+     * present as an RSA_OAEP_MGF_DIGEST value in the key characteristics (or the begin() operation
+     * must fail with ErrorCode::INCOMPATIBLE_MGF_DIGEST).
+     *
+     * If the caller does not specify an MGF1 digest in the params argument of begin(), a default
+     * MGF1 digest of SHA1 is used.  If the key characteristics have any explicitly specified values
+     * for RSA_OAEP_MGF_DIGEST, then SHA1 must be included (or the begin() operation must fail with
+     * ErrorCode::INCOMPATIBLE_MGF_DIGEST).
      *
      * Must be hardware-enforced.
      */
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index 240de35..ca517ac 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "keymint_1_attest_key_test"
 #include <cutils/log.h>
+#include <cutils/properties.h>
 
 #include <keymint_support/key_param_output.h>
 #include <keymint_support/openssl_utils.h>
@@ -33,7 +34,33 @@
 
 }  // namespace
 
-using AttestKeyTest = KeyMintAidlTestBase;
+class AttestKeyTest : public KeyMintAidlTestBase {
+  protected:
+    ErrorCode GenerateAttestKey(const AuthorizationSet& key_desc,
+                                const optional<AttestationKey>& attest_key,
+                                vector<uint8_t>* key_blob,
+                                vector<KeyCharacteristics>* key_characteristics,
+                                vector<Certificate>* cert_chain) {
+        // The original specification for KeyMint v1 required ATTEST_KEY not be combined
+        // with any other key purpose, but the original VTS tests incorrectly did exactly that.
+        // This means that a device that launched prior to Android T (API level 33) may
+        // accept or even require KeyPurpose::SIGN too.
+        if (property_get_int32("ro.board.first_api_level", 0) < 33) {
+            AuthorizationSet key_desc_plus_sign = key_desc;
+            key_desc_plus_sign.push_back(TAG_PURPOSE, KeyPurpose::SIGN);
+
+            auto result = GenerateKey(key_desc_plus_sign, attest_key, key_blob, key_characteristics,
+                                      cert_chain);
+            if (result == ErrorCode::OK) {
+                return result;
+            }
+            // If the key generation failed, it may be because the device is (correctly)
+            // rejecting the combination of ATTEST_KEY+SIGN.  Fall through to try again with
+            // just ATTEST_KEY.
+        }
+        return GenerateKey(key_desc, attest_key, key_blob, key_characteristics, cert_chain);
+    }
+};
 
 /*
  * AttestKeyTest.AllRsaSizes
@@ -49,12 +76,13 @@
         AttestationKey attest_key;
         vector<KeyCharacteristics> attest_key_characteristics;
         vector<Certificate> attest_key_cert_chain;
-        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                     .RsaKey(size, 65537)
-                                                     .AttestKey()
-                                                     .SetDefaultValidity(),
-                                             {} /* attestation signing key */, &attest_key.keyBlob,
-                                             &attest_key_characteristics, &attest_key_cert_chain));
+        ASSERT_EQ(ErrorCode::OK,
+                  GenerateAttestKey(AuthorizationSetBuilder()
+                                            .RsaKey(size, 65537)
+                                            .AttestKey()
+                                            .SetDefaultValidity(),
+                                    {} /* attestation signing key */, &attest_key.keyBlob,
+                                    &attest_key_characteristics, &attest_key_cert_chain));
 
         ASSERT_GT(attest_key_cert_chain.size(), 0);
         EXPECT_EQ(attest_key_cert_chain.size(), 1);
@@ -227,17 +255,17 @@
     AttestationKey attest_key;
     vector<KeyCharacteristics> attest_key_characteristics;
     vector<Certificate> attest_key_cert_chain;
-    auto result = GenerateKey(AuthorizationSetBuilder()
-                                      .RsaKey(2048, 65537)
-                                      .AttestKey()
-                                      .AttestationChallenge(challenge)
-                                      .AttestationApplicationId(app_id)
-                                      .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                      .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                      .Authorization(TAG_NO_AUTH_REQUIRED)
-                                      .SetDefaultValidity(),
-                              {} /* attestation signing key */, &attest_key.keyBlob,
-                              &attest_key_characteristics, &attest_key_cert_chain);
+    auto result = GenerateAttestKey(AuthorizationSetBuilder()
+                                            .RsaKey(2048, 65537)
+                                            .AttestKey()
+                                            .AttestationChallenge(challenge)
+                                            .AttestationApplicationId(app_id)
+                                            .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                            .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                            .Authorization(TAG_NO_AUTH_REQUIRED)
+                                            .SetDefaultValidity(),
+                                    {} /* attestation signing key */, &attest_key.keyBlob,
+                                    &attest_key_characteristics, &attest_key_cert_chain);
     // Strongbox may not support factory provisioned attestation key.
     if (SecLevel() == SecurityLevel::STRONGBOX) {
         if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
@@ -331,17 +359,17 @@
             attest_key_opt = attest_key;
         }
 
-        auto result = GenerateKey(AuthorizationSetBuilder()
-                                          .RsaKey(2048, 65537)
-                                          .AttestKey()
-                                          .AttestationChallenge("foo")
-                                          .AttestationApplicationId("bar")
-                                          .Authorization(TAG_NO_AUTH_REQUIRED)
-                                          .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                          .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                          .SetDefaultValidity(),
-                                  attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
-                                  &cert_chain_list[i]);
+        auto result = GenerateAttestKey(AuthorizationSetBuilder()
+                                                .RsaKey(2048, 65537)
+                                                .AttestKey()
+                                                .AttestationChallenge("foo")
+                                                .AttestationApplicationId("bar")
+                                                .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                                .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                                .SetDefaultValidity(),
+                                        attest_key_opt, &key_blob_list[i],
+                                        &attested_key_characteristics, &cert_chain_list[i]);
         // Strongbox may not support factory provisioned attestation key.
         if (SecLevel() == SecurityLevel::STRONGBOX) {
             if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
@@ -408,17 +436,17 @@
             attest_key_opt = attest_key;
         }
 
-        auto result = GenerateKey(AuthorizationSetBuilder()
-                                          .EcdsaKey(EcCurve::P_256)
-                                          .AttestKey()
-                                          .AttestationChallenge("foo")
-                                          .AttestationApplicationId("bar")
-                                          .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                          .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                          .Authorization(TAG_NO_AUTH_REQUIRED)
-                                          .SetDefaultValidity(),
-                                  attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
-                                  &cert_chain_list[i]);
+        auto result = GenerateAttestKey(AuthorizationSetBuilder()
+                                                .EcdsaKey(EcCurve::P_256)
+                                                .AttestKey()
+                                                .AttestationChallenge("foo")
+                                                .AttestationApplicationId("bar")
+                                                .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                                .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                                .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                .SetDefaultValidity(),
+                                        attest_key_opt, &key_blob_list[i],
+                                        &attested_key_characteristics, &cert_chain_list[i]);
         // Strongbox may not support factory provisioned attestation key.
         if (SecLevel() == SecurityLevel::STRONGBOX) {
             if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
@@ -513,29 +541,29 @@
         }
         ErrorCode result;
         if ((i & 0x1) == 1) {
-            result = GenerateKey(AuthorizationSetBuilder()
-                                         .EcdsaKey(EcCurve::P_256)
-                                         .AttestKey()
-                                         .AttestationChallenge("foo")
-                                         .AttestationApplicationId("bar")
-                                         .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                         .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                         .Authorization(TAG_NO_AUTH_REQUIRED)
-                                         .SetDefaultValidity(),
-                                 attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
-                                 &cert_chain_list[i]);
+            result = GenerateAttestKey(AuthorizationSetBuilder()
+                                               .EcdsaKey(EcCurve::P_256)
+                                               .AttestKey()
+                                               .AttestationChallenge("foo")
+                                               .AttestationApplicationId("bar")
+                                               .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                               .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .SetDefaultValidity(),
+                                       attest_key_opt, &key_blob_list[i],
+                                       &attested_key_characteristics, &cert_chain_list[i]);
         } else {
-            result = GenerateKey(AuthorizationSetBuilder()
-                                         .RsaKey(2048, 65537)
-                                         .AttestKey()
-                                         .AttestationChallenge("foo")
-                                         .AttestationApplicationId("bar")
-                                         .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                         .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                         .Authorization(TAG_NO_AUTH_REQUIRED)
-                                         .SetDefaultValidity(),
-                                 attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
-                                 &cert_chain_list[i]);
+            result = GenerateAttestKey(AuthorizationSetBuilder()
+                                               .RsaKey(2048, 65537)
+                                               .AttestKey()
+                                               .AttestationChallenge("foo")
+                                               .AttestationApplicationId("bar")
+                                               .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                               .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .SetDefaultValidity(),
+                                       attest_key_opt, &key_blob_list[i],
+                                       &attested_key_characteristics, &cert_chain_list[i]);
         }
         // Strongbox may not support factory provisioned attestation key.
         if (SecLevel() == SecurityLevel::STRONGBOX) {
@@ -581,12 +609,13 @@
         AttestationKey attest_key;
         vector<KeyCharacteristics> attest_key_characteristics;
         vector<Certificate> attest_key_cert_chain;
-        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                     .RsaKey(size, 65537)
-                                                     .AttestKey()
-                                                     .SetDefaultValidity(),
-                                             {} /* attestation signing key */, &attest_key.keyBlob,
-                                             &attest_key_characteristics, &attest_key_cert_chain));
+        ASSERT_EQ(ErrorCode::OK,
+                  GenerateAttestKey(AuthorizationSetBuilder()
+                                            .RsaKey(size, 65537)
+                                            .AttestKey()
+                                            .SetDefaultValidity(),
+                                    {} /* attestation signing key */, &attest_key.keyBlob,
+                                    &attest_key_characteristics, &attest_key_cert_chain));
 
         EXPECT_EQ(attest_key_cert_chain.size(), 1);
         EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain)) << "Failed on size " << size;
@@ -630,7 +659,7 @@
         vector<Certificate> attest_key_cert_chain;
         ASSERT_EQ(
                 ErrorCode::OK,
-                GenerateKey(
+                GenerateAttestKey(
                         AuthorizationSetBuilder().EcdsaKey(curve).AttestKey().SetDefaultValidity(),
                         {} /* attestation signing key */, &attest_key.keyBlob,
                         &attest_key_characteristics, &attest_key_cert_chain));
@@ -752,12 +781,13 @@
     AttestationKey attest_key;
     vector<KeyCharacteristics> attest_key_characteristics;
     vector<Certificate> attest_key_cert_chain;
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                 .EcdsaKey(EcCurve::P_256)
-                                                 .AttestKey()
-                                                 .SetDefaultValidity(),
-                                         {} /* attestation signing key */, &attest_key.keyBlob,
-                                         &attest_key_characteristics, &attest_key_cert_chain));
+    ASSERT_EQ(ErrorCode::OK,
+              GenerateAttestKey(AuthorizationSetBuilder()
+                                        .EcdsaKey(EcCurve::P_256)
+                                        .AttestKey()
+                                        .SetDefaultValidity(),
+                                {} /* attestation signing key */, &attest_key.keyBlob,
+                                &attest_key_characteristics, &attest_key_cert_chain));
     attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
     ASSERT_GT(attest_key_cert_chain.size(), 0);
     EXPECT_EQ(attest_key_cert_chain.size(), 1);
@@ -816,12 +846,13 @@
     AttestationKey attest_key;
     vector<KeyCharacteristics> attest_key_characteristics;
     vector<Certificate> attest_key_cert_chain;
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                 .EcdsaKey(EcCurve::P_256)
-                                                 .AttestKey()
-                                                 .SetDefaultValidity(),
-                                         {} /* attestation signing key */, &attest_key.keyBlob,
-                                         &attest_key_characteristics, &attest_key_cert_chain));
+    ASSERT_EQ(ErrorCode::OK,
+              GenerateAttestKey(AuthorizationSetBuilder()
+                                        .EcdsaKey(EcCurve::P_256)
+                                        .AttestKey()
+                                        .SetDefaultValidity(),
+                                {} /* attestation signing key */, &attest_key.keyBlob,
+                                &attest_key_characteristics, &attest_key_cert_chain));
     attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
     ASSERT_GT(attest_key_cert_chain.size(), 0);
     EXPECT_EQ(attest_key_cert_chain.size(), 1);
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index be21994..46db4f0 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -31,7 +31,6 @@
 #include <remote_prov/remote_prov_utils.h>
 
 #include <keymaster/cppcose/cppcose.h>
-#include <keymint_support/attestation_record.h>
 #include <keymint_support/key_param_output.h>
 #include <keymint_support/keymint_utils.h>
 #include <keymint_support/openssl_utils.h>
@@ -1461,6 +1460,31 @@
     OPENSSL_free(cert_issuer);
 }
 
+int get_vsr_api_level() {
+    int vendor_api_level = ::android::base::GetIntProperty("ro.vendor.api_level", -1);
+    if (vendor_api_level != -1) {
+        return vendor_api_level;
+    }
+
+    // Android S and older devices do not define ro.vendor.api_level
+    vendor_api_level = ::android::base::GetIntProperty("ro.board.api_level", -1);
+    if (vendor_api_level == -1) {
+        vendor_api_level = ::android::base::GetIntProperty("ro.board.first_api_level", -1);
+    }
+
+    int product_api_level = ::android::base::GetIntProperty("ro.product.first_api_level", -1);
+    if (product_api_level == -1) {
+        product_api_level = ::android::base::GetIntProperty("ro.build.version.sdk", -1);
+        EXPECT_NE(product_api_level, -1) << "Could not find ro.build.version.sdk";
+    }
+
+    // VSR API level is the minimum of vendor_api_level and product_api_level.
+    if (vendor_api_level == -1 || vendor_api_level > product_api_level) {
+        return product_api_level;
+    }
+    return vendor_api_level;
+}
+
 bool is_gsi_image() {
     std::ifstream ifs("/system/system_ext/etc/init/init.gsi.rc");
     return ifs.good();
@@ -1497,6 +1521,60 @@
     verify_subject(cert.get(), subject, self_signed);
 }
 
+void verify_root_of_trust(const vector<uint8_t>& verified_boot_key, bool device_locked,
+                          VerifiedBoot verified_boot_state,
+                          const vector<uint8_t>& verified_boot_hash) {
+    char property_value[PROPERTY_VALUE_MAX] = {};
+
+    if (avb_verification_enabled()) {
+        EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
+        string prop_string(property_value);
+        EXPECT_EQ(prop_string.size(), 64);
+        EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
+
+        EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
+        if (!strcmp(property_value, "unlocked")) {
+            EXPECT_FALSE(device_locked);
+        } else {
+            EXPECT_TRUE(device_locked);
+        }
+
+        // Check that the device is locked if not debuggable, e.g., user build
+        // images in CTS. For VTS, debuggable images are used to allow adb root
+        // and the device is unlocked.
+        if (!property_get_bool("ro.debuggable", false)) {
+            EXPECT_TRUE(device_locked);
+        } else {
+            EXPECT_FALSE(device_locked);
+        }
+    }
+
+    // Verified boot key should be all 0's if the boot state is not verified or self signed
+    std::string empty_boot_key(32, '\0');
+    std::string verified_boot_key_str((const char*)verified_boot_key.data(),
+                                      verified_boot_key.size());
+    EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
+    if (!strcmp(property_value, "green")) {
+        EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
+        EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+                            verified_boot_key.size()));
+    } else if (!strcmp(property_value, "yellow")) {
+        EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED);
+        EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+                            verified_boot_key.size()));
+    } else if (!strcmp(property_value, "orange")) {
+        EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
+        EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+                            verified_boot_key.size()));
+    } else if (!strcmp(property_value, "red")) {
+        EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED);
+    } else {
+        EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
+        EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+                            verified_boot_key.size()));
+    }
+}
+
 bool verify_attestation_record(int32_t aidl_version,                   //
                                const string& challenge,                //
                                const string& app_id,                   //
@@ -1551,8 +1629,6 @@
     EXPECT_EQ(security_level, att_keymint_security_level);
     EXPECT_EQ(security_level, att_attestation_security_level);
 
-
-    char property_value[PROPERTY_VALUE_MAX] = {};
     // TODO(b/136282179): When running under VTS-on-GSI the TEE-backed
     // keymint implementation will report YYYYMM dates instead of YYYYMMDD
     // for the BOOT_PATCH_LEVEL.
@@ -1612,54 +1688,7 @@
     error = parse_root_of_trust(attest_rec->data, attest_rec->length, &verified_boot_key,
                                 &verified_boot_state, &device_locked, &verified_boot_hash);
     EXPECT_EQ(ErrorCode::OK, error);
-
-    if (avb_verification_enabled()) {
-        EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
-        string prop_string(property_value);
-        EXPECT_EQ(prop_string.size(), 64);
-        EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
-
-        EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
-        if (!strcmp(property_value, "unlocked")) {
-            EXPECT_FALSE(device_locked);
-        } else {
-            EXPECT_TRUE(device_locked);
-        }
-
-        // Check that the device is locked if not debuggable, e.g., user build
-        // images in CTS. For VTS, debuggable images are used to allow adb root
-        // and the device is unlocked.
-        if (!property_get_bool("ro.debuggable", false)) {
-            EXPECT_TRUE(device_locked);
-        } else {
-            EXPECT_FALSE(device_locked);
-        }
-    }
-
-    // Verified boot key should be all 0's if the boot state is not verified or self signed
-    std::string empty_boot_key(32, '\0');
-    std::string verified_boot_key_str((const char*)verified_boot_key.data(),
-                                      verified_boot_key.size());
-    EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
-    if (!strcmp(property_value, "green")) {
-        EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
-        EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
-                            verified_boot_key.size()));
-    } else if (!strcmp(property_value, "yellow")) {
-        EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED);
-        EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
-                            verified_boot_key.size()));
-    } else if (!strcmp(property_value, "orange")) {
-        EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
-        EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
-                            verified_boot_key.size()));
-    } else if (!strcmp(property_value, "red")) {
-        EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED);
-    } else {
-        EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
-        EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
-                            verified_boot_key.size()));
-    }
+    verify_root_of_trust(verified_boot_key, device_locked, verified_boot_state, verified_boot_hash);
 
     att_sw_enforced.Sort();
     expected_sw_enforced.Sort();
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 2634ab7..8f9df24 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -31,6 +31,7 @@
 #include <aidl/android/hardware/security/keymint/IKeyMintDevice.h>
 #include <aidl/android/hardware/security/keymint/MacedPublicKey.h>
 
+#include <keymint_support/attestation_record.h>
 #include <keymint_support/authorization_set.h>
 #include <keymint_support/openssl_utils.h>
 
@@ -354,6 +355,9 @@
     }
 }
 
+// Return the VSR API level for this device.
+int get_vsr_api_level();
+
 // Indicate whether the test is running on a GSI image.
 bool is_gsi_image();
 
@@ -363,7 +367,10 @@
 void verify_subject_and_serial(const Certificate& certificate,  //
                                const uint64_t expected_serial,  //
                                const string& subject, bool self_signed);
-
+void verify_root_of_trust(const vector<uint8_t>& verified_boot_key,  //
+                          bool device_locked,                        //
+                          VerifiedBoot verified_boot_state,          //
+                          const vector<uint8_t>& verified_boot_hash);
 bool verify_attestation_record(int aidl_version,                       //
                                const string& challenge,                //
                                const string& app_id,                   //
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 7950850..7c398d3 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -613,7 +613,7 @@
 class NewKeyGenerationTest : public KeyMintAidlTestBase {
   protected:
     void CheckBaseParams(const vector<KeyCharacteristics>& keyCharacteristics) {
-        AuthorizationSet auths = CheckCommonParams(keyCharacteristics);
+        AuthorizationSet auths = CheckCommonParams(keyCharacteristics, KeyOrigin::GENERATED);
         EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::SIGN));
 
         // Check that some unexpected tags/values are NOT present.
@@ -622,20 +622,21 @@
     }
 
     void CheckSymmetricParams(const vector<KeyCharacteristics>& keyCharacteristics) {
-        AuthorizationSet auths = CheckCommonParams(keyCharacteristics);
+        AuthorizationSet auths = CheckCommonParams(keyCharacteristics, KeyOrigin::GENERATED);
         EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::ENCRYPT));
         EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::DECRYPT));
 
         EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::SIGN));
     }
 
-    AuthorizationSet CheckCommonParams(const vector<KeyCharacteristics>& keyCharacteristics) {
+    AuthorizationSet CheckCommonParams(const vector<KeyCharacteristics>& keyCharacteristics,
+                                       const KeyOrigin expectedKeyOrigin) {
         // TODO(swillden): Distinguish which params should be in which auth list.
         AuthorizationSet auths;
         for (auto& entry : keyCharacteristics) {
             auths.push_back(AuthorizationSet(entry.authorizations));
         }
-        EXPECT_TRUE(auths.Contains(TAG_ORIGIN, KeyOrigin::GENERATED));
+        EXPECT_TRUE(auths.Contains(TAG_ORIGIN, expectedKeyOrigin));
 
         // Verify that App data, ROT and auth timeout are NOT included.
         EXPECT_FALSE(auths.Contains(TAG_ROOT_OF_TRUST));
@@ -1102,9 +1103,9 @@
                 << "Key size " << key_size << "missing";
         EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
 
+        ASSERT_GT(cert_chain_.size(), 0);
         verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
         EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
-        ASSERT_GT(cert_chain_.size(), 0);
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
@@ -1178,6 +1179,7 @@
         EXPECT_FALSE(ChainSignaturesAreValid(cert_chain_));
 
         // The signature over the attested key should correspond to the P256 public key.
+        ASSERT_GT(cert_chain_.size(), 0);
         X509_Ptr key_cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
         ASSERT_TRUE(key_cert.get());
         EVP_PKEY_Ptr signing_pubkey;
@@ -1265,9 +1267,9 @@
             << "Key size " << key_size << "missing";
     EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
 
+    ASSERT_GT(cert_chain_.size(), 0);
     verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
     EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
-    ASSERT_GT(cert_chain_.size(), 0);
 
     AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
     AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
@@ -1317,9 +1319,9 @@
                 << "Key size " << key_size << "missing";
         EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
 
+        ASSERT_EQ(cert_chain_.size(), 1);
         verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
         EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
-        ASSERT_EQ(cert_chain_.size(), 1);
 
         CheckedDeleteKey(&key_blob);
     }
@@ -1398,6 +1400,7 @@
             << "Key size " << key_size << "missing";
     EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
 
+    ASSERT_GT(cert_chain_.size(), 0);
     verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
     EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
     ASSERT_EQ(cert_chain_.size(), 1);
@@ -2228,8 +2231,8 @@
         EXPECT_TRUE(crypto_params.Contains(TAG_EC_CURVE, curve)) << "Curve " << curve << "missing";
 
         EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
-        verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
         ASSERT_EQ(cert_chain_.size(), 1);
+        verify_subject_and_serial(cert_chain_[0], serial_int, subject, false);
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
@@ -2448,6 +2451,29 @@
 }
 
 /*
+ * NewKeyGenerationTest.EcdsaMissingCurve
+ *
+ * Verifies that EC key generation fails if EC_CURVE not specified after KeyMint V2.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaMissingCurve) {
+    if (AidlVersion() < 2) {
+        /*
+         * The KeyMint V1 spec required that EC_CURVE be specified for EC keys.
+         * However, this was not checked at the time so we can only be strict about checking this
+         * for implementations of KeyMint version 2 and above.
+         */
+        GTEST_SKIP() << "Requiring EC_CURVE only strict since KeyMint v2";
+    }
+    /* If EC_CURVE not provided, generateKey
+     * must return ErrorCode::UNSUPPORTED_KEY_SIZE or ErrorCode::UNSUPPORTED_EC_CURVE.
+     */
+    auto result = GenerateKey(
+            AuthorizationSetBuilder().EcdsaKey(256).Digest(Digest::NONE).SetDefaultValidity());
+    ASSERT_TRUE(result == ErrorCode::UNSUPPORTED_KEY_SIZE ||
+                result == ErrorCode::UNSUPPORTED_EC_CURVE);
+}
+
+/*
  * NewKeyGenerationTest.EcdsaMismatchKeySize
  *
  * Verifies that specifying mismatched key size and curve for EC key generation returns
@@ -3776,7 +3802,7 @@
 // TODO(seleneh) add ExportKey to GenerateKey
 // check result
 
-class ImportKeyTest : public KeyMintAidlTestBase {
+class ImportKeyTest : public NewKeyGenerationTest {
   public:
     template <TagType tag_type, Tag tag, typename ValueT>
     void CheckCryptoParam(TypedTag<tag_type, tag> ttag, ValueT expected) {
@@ -4486,6 +4512,65 @@
     VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
 }
 
+/*
+ * ImportKeyTest.GetKeyCharacteristics
+ *
+ * Verifies that imported keys have the correct characteristics.
+ */
+TEST_P(ImportKeyTest, GetKeyCharacteristics) {
+    vector<uint8_t> key_blob;
+    vector<KeyCharacteristics> key_characteristics;
+    auto base_builder = AuthorizationSetBuilder()
+                                .Padding(PaddingMode::NONE)
+                                .Authorization(TAG_NO_AUTH_REQUIRED)
+                                .SetDefaultValidity();
+    vector<Algorithm> algorithms = {Algorithm::RSA, Algorithm::EC, Algorithm::HMAC, Algorithm::AES,
+                                    Algorithm::TRIPLE_DES};
+    ErrorCode result;
+    string symKey = hex2str("a49d7564199e97cb529d2c9d97bf2f98");                   // 128 bits
+    string tdesKey = hex2str("a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358");  // 192 bits
+    for (auto alg : algorithms) {
+        SCOPED_TRACE(testing::Message() << "Algorithm-" << alg);
+        AuthorizationSetBuilder builder(base_builder);
+        switch (alg) {
+            case Algorithm::RSA:
+                builder.RsaSigningKey(2048, 65537).Digest(Digest::NONE);
+
+                result = ImportKey(builder, KeyFormat::PKCS8, rsa_2048_key, &key_blob,
+                                   &key_characteristics);
+                break;
+            case Algorithm::EC:
+                builder.EcdsaSigningKey(EcCurve::P_256).Digest(Digest::NONE);
+                result = ImportKey(builder, KeyFormat::PKCS8, ec_256_key, &key_blob,
+                                   &key_characteristics);
+                break;
+            case Algorithm::HMAC:
+                builder.HmacKey(128)
+                        .Digest(Digest::SHA_2_256)
+                        .Authorization(TAG_MIN_MAC_LENGTH, 128);
+                result =
+                        ImportKey(builder, KeyFormat::RAW, symKey, &key_blob, &key_characteristics);
+                break;
+            case Algorithm::AES:
+                builder.AesEncryptionKey(128).BlockMode(BlockMode::ECB);
+                result =
+                        ImportKey(builder, KeyFormat::RAW, symKey, &key_blob, &key_characteristics);
+                break;
+            case Algorithm::TRIPLE_DES:
+                builder.TripleDesEncryptionKey(168).BlockMode(BlockMode::ECB);
+                result = ImportKey(builder, KeyFormat::RAW, tdesKey, &key_blob,
+                                   &key_characteristics);
+                break;
+            default:
+                ADD_FAILURE() << "Invalid Algorithm " << uint32_t(alg);
+                continue;
+        }
+        ASSERT_EQ(ErrorCode::OK, result);
+        CheckCharacteristics(key_blob, key_characteristics);
+        CheckCommonParams(key_characteristics, KeyOrigin::IMPORTED);
+    }
+}
+
 INSTANTIATE_KEYMINT_AIDL_TEST(ImportKeyTest);
 
 auto wrapped_key = hex2str(
@@ -6163,7 +6248,7 @@
 
     // Encrypt
     AuthorizationSet begin_out_params;
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
     string ciphertext;
     AuthorizationSet finish_out_params;
     ASSERT_EQ(ErrorCode::OK, UpdateAad(aad));
@@ -6206,7 +6291,7 @@
                                 .Authorization(TAG_MAC_LENGTH, tag_bits);
     AuthorizationSet begin_out_params;
 
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
 
     // No data, AAD only.
     EXPECT_EQ(ErrorCode::OK, UpdateAad("foo"));
@@ -6222,7 +6307,7 @@
     begin_params.push_back(begin_out_params);
 
     // Decrypt
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
     EXPECT_EQ(ErrorCode::OK, UpdateAad("foofoo"));
     string plaintext;
     EXPECT_EQ(ErrorCode::OK, Finish(ciphertext, &plaintext));
@@ -6249,7 +6334,7 @@
                                 .Authorization(TAG_MAC_LENGTH, 128);
     AuthorizationSet begin_out_params;
 
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
 
     EXPECT_EQ(ErrorCode::OK, UpdateAad("foo"));
     string ciphertext;
@@ -6283,7 +6368,7 @@
 
     // Encrypt
     AuthorizationSet begin_out_params;
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
     EXPECT_EQ(ErrorCode::OK, UpdateAad("foobar"));
     string ciphertext;
     EXPECT_EQ(ErrorCode::OK, Finish(message, &ciphertext));
@@ -6292,7 +6377,7 @@
     begin_params.push_back(begin_out_params);
 
     // Decrypt.
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
     EXPECT_EQ(ErrorCode::OK, UpdateAad("barfoo"));
     string plaintext;
     EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext));
@@ -6319,7 +6404,7 @@
 
     // Encrypt
     AuthorizationSet begin_out_params;
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
     EXPECT_EQ(ErrorCode::OK, UpdateAad("foobar"));
     string ciphertext;
     AuthorizationSet finish_out_params;
@@ -6329,7 +6414,7 @@
     begin_params.push_back(TAG_NONCE, AidlBuf("123456789012"));
 
     // Decrypt.
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
     EXPECT_EQ(ErrorCode::OK, UpdateAad("foobar"));
     string plaintext;
     EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext));
@@ -6361,7 +6446,7 @@
 
     // Encrypt
     AuthorizationSet begin_out_params;
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
     EXPECT_EQ(ErrorCode::OK, UpdateAad(aad));
     string ciphertext;
     EXPECT_EQ(ErrorCode::OK, Finish(message, &ciphertext));
@@ -6373,7 +6458,7 @@
     params.push_back(begin_out_params);
 
     // Decrypt.
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
     EXPECT_EQ(ErrorCode::OK, UpdateAad(aad));
     string plaintext;
     EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext));
@@ -6486,7 +6571,7 @@
     for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
         ++ciphertext[ciphertext.size() / 2];
 
-        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+        ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
         string plaintext;
         EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext));
         ErrorCode error = Finish(&plaintext);
@@ -6758,7 +6843,7 @@
         auto begin_params =
                 AuthorizationSetBuilder().BlockMode(blockMode).Padding(PaddingMode::NONE);
         AuthorizationSet output_params;
-        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &output_params));
+        ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &output_params));
         string ciphertext;
         EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, "", &ciphertext));
 
@@ -6837,7 +6922,7 @@
     for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
         SCOPED_TRACE(testing::Message() << "i = " << i);
         ++ciphertext[ciphertext.size() / 2];
-        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+        ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
         string plaintext;
         EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext));
         ErrorCode error = Finish(&plaintext);
@@ -6869,7 +6954,7 @@
     AuthorizationSet input_params =
             AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
     AuthorizationSet output_params;
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
 
     string ciphertext;
     for (size_t i = 0; i < message.size(); i += increment)
@@ -6883,7 +6968,7 @@
     input_params.push_back(TAG_PADDING, PaddingMode::NONE);
     output_params.Clear();
 
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, input_params, &output_params));
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, input_params, &output_params));
     string plaintext;
     for (size_t i = 0; i < ciphertext.size(); i += increment)
         EXPECT_EQ(ErrorCode::OK, Update(ciphertext.substr(i, increment), &plaintext));
@@ -7000,7 +7085,7 @@
     } else {
         // Usage count limit tag is enforced by keystore, keymint does nothing.
         EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U));
-        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+        ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
     }
 }
 
@@ -7047,7 +7132,7 @@
     } else {
         // Usage count limit tag is enforced by keystore, keymint does nothing.
         EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 3U));
-        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+        ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
     }
 }
 
@@ -7093,7 +7178,7 @@
     } else {
         // Usage count limit tag is enforced by keystore, keymint does nothing.
         EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U));
-        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
+        ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
     }
 }
 
@@ -7140,7 +7225,7 @@
     } else {
         // Usage count limit tag is enforced by keystore, keymint does nothing.
         EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 3U));
-        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
+        ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
     }
 }
 
@@ -7453,7 +7538,7 @@
         EXPECT_EQ(ErrorCode::OK, Abort(op_handles[j]))
                 << "Aboort failed for i = " << j << std::endl;
     }
-    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, key_blob_, params, &out_params));
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, key_blob_, params, &out_params));
     AbortIfNeeded();
 }
 
@@ -7478,7 +7563,7 @@
                 AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
 
         AuthorizationSet out_params;
-        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, cipher_params, &out_params));
+        ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, cipher_params, &out_params));
 
         string plain_message = std::string(1 << msg_size, 'x');
         string encrypted_message;
@@ -7489,7 +7574,7 @@
                 << "Encrypt finish returned OK, but did not consume all of the given input";
         cipher_params.push_back(out_params);
 
-        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params));
+        ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params));
 
         string decrypted_message;
         rc = Finish(encrypted_message, &decrypted_message);
@@ -7525,7 +7610,6 @@
             uint8_t privKeyData[32];
             uint8_t pubKeyData[32];
             X25519_keypair(pubKeyData, privKeyData);
-            *localPublicKey = vector<uint8_t>(pubKeyData, pubKeyData + 32);
             *localPrivKey = EVP_PKEY_Ptr(EVP_PKEY_new_raw_private_key(
                     EVP_PKEY_X25519, nullptr, privKeyData, sizeof(privKeyData)));
         } else {
@@ -7537,16 +7621,15 @@
             ASSERT_EQ(EC_KEY_generate_key(ecKey.get()), 1);
             *localPrivKey = EVP_PKEY_Ptr(EVP_PKEY_new());
             ASSERT_EQ(EVP_PKEY_set1_EC_KEY(localPrivKey->get(), ecKey.get()), 1);
-
-            // Get encoded form of the public part of the locally generated key...
-            unsigned char* p = nullptr;
-            int localPublicKeySize = i2d_PUBKEY(localPrivKey->get(), &p);
-            ASSERT_GT(localPublicKeySize, 0);
-            *localPublicKey =
-                    vector<uint8_t>(reinterpret_cast<const uint8_t*>(p),
-                                    reinterpret_cast<const uint8_t*>(p + localPublicKeySize));
-            OPENSSL_free(p);
         }
+
+        // Get encoded form of the public part of the locally generated key...
+        unsigned char* p = nullptr;
+        int localPublicKeySize = i2d_PUBKEY(localPrivKey->get(), &p);
+        ASSERT_GT(localPublicKeySize, 0);
+        *localPublicKey = vector<uint8_t>(reinterpret_cast<const uint8_t*>(p),
+                                          reinterpret_cast<const uint8_t*>(p + localPublicKeySize));
+        OPENSSL_free(p);
     }
 
     void GenerateKeyMintEcKey(EcCurve curve, EVP_PKEY_Ptr* kmPubKey) {
@@ -7641,6 +7724,9 @@
     //
     for (auto curve : ValidCurves()) {
         for (auto localCurve : ValidCurves()) {
+            SCOPED_TRACE(testing::Message()
+                         << "local-curve-" << localCurve << "-keymint-curve-" << curve);
+
             // Generate EC key locally (with access to private key material)
             EVP_PKEY_Ptr localPrivKey;
             vector<uint8_t> localPublicKey;
@@ -7654,7 +7740,7 @@
             if (curve != localCurve) {
                 // If the keys are using different curves KeyMint should fail with
                 // ErrorCode:INVALID_ARGUMENT. Check that.
-                EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
+                ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
                 string ZabFromKeyMintStr;
                 EXPECT_EQ(ErrorCode::INVALID_ARGUMENT,
                           Finish(string(localPublicKey.begin(), localPublicKey.end()),
@@ -7794,7 +7880,7 @@
         vector<uint8_t> encodedPublicKey;
         GenerateLocalEcKey(localCurve, &privKey, &encodedPublicKey);
 
-        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
+        ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
         string ZabFromKeyMintStr;
         EXPECT_EQ(ErrorCode::INVALID_ARGUMENT,
                   Finish(string(encodedPublicKey.begin(), encodedPublicKey.end()),
@@ -7990,6 +8076,18 @@
 
 INSTANTIATE_KEYMINT_AIDL_TEST(UnlockedDeviceRequiredTest);
 
+using VsrRequirementTest = KeyMintAidlTestBase;
+
+TEST_P(VsrRequirementTest, Vsr13Test) {
+    int vsr_api_level = get_vsr_api_level();
+    if (vsr_api_level < 33) {
+        GTEST_SKIP() << "Applies only to VSR API level 33, this device is: " << vsr_api_level;
+    }
+    EXPECT_GE(AidlVersion(), 2) << "VSR 13+ requires KeyMint version 2";
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(VsrRequirementTest);
+
 }  // namespace aidl::android::hardware::security::keymint::test
 
 int main(int argc, char** argv) {
diff --git a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
index e630f70..c9a156d 100644
--- a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
+++ b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
@@ -36,6 +36,8 @@
 using std::shared_ptr;
 using std::vector;
 
+constexpr int kRoTVersion1 = 40001;
+
 class SecureElementProvisioningTest : public testing::Test {
   protected:
     static void SetUpTestSuite() {
@@ -57,6 +59,83 @@
         }
     }
 
+    void validateMacedRootOfTrust(const vector<uint8_t>& rootOfTrust) {
+        SCOPED_TRACE(testing::Message() << "RoT: " << bin2hex(rootOfTrust));
+
+        const auto [macItem, macEndPos, macErrMsg] = cppbor::parse(rootOfTrust);
+        ASSERT_TRUE(macItem) << "Root of trust parsing failed: " << macErrMsg;
+        ASSERT_EQ(macItem->semanticTagCount(), 1);
+        ASSERT_EQ(macItem->semanticTag(0), cppcose::kCoseMac0SemanticTag);
+        ASSERT_TRUE(macItem->asArray());
+        ASSERT_EQ(macItem->asArray()->size(), cppcose::kCoseMac0EntryCount);
+
+        const auto& protectedItem = macItem->asArray()->get(cppcose::kCoseMac0ProtectedParams);
+        ASSERT_TRUE(protectedItem);
+        ASSERT_TRUE(protectedItem->asBstr());
+        const auto [protMap, protEndPos, protErrMsg] = cppbor::parse(protectedItem->asBstr());
+        ASSERT_TRUE(protMap);
+        ASSERT_TRUE(protMap->asMap());
+        ASSERT_EQ(protMap->asMap()->size(), 1);
+
+        const auto& algorithm = protMap->asMap()->get(cppcose::ALGORITHM);
+        ASSERT_TRUE(algorithm);
+        ASSERT_TRUE(algorithm->asInt());
+        ASSERT_EQ(algorithm->asInt()->value(), cppcose::HMAC_256);
+
+        const auto& unprotItem = macItem->asArray()->get(cppcose::kCoseMac0UnprotectedParams);
+        ASSERT_TRUE(unprotItem);
+        ASSERT_TRUE(unprotItem->asMap());
+        ASSERT_EQ(unprotItem->asMap()->size(), 0);
+
+        const auto& payload = macItem->asArray()->get(cppcose::kCoseMac0Payload);
+        ASSERT_TRUE(payload);
+        ASSERT_TRUE(payload->asBstr());
+        validateRootOfTrust(payload->asBstr()->value());
+
+        const auto& tag = macItem->asArray()->get(cppcose::kCoseMac0Tag);
+        ASSERT_TRUE(tag);
+        ASSERT_TRUE(tag->asBstr());
+        ASSERT_EQ(tag->asBstr()->value().size(), 32);
+        // Cannot validate tag correctness.  Only the secure side has the necessary key.
+    }
+
+    void validateRootOfTrust(const vector<uint8_t>& payload) {
+        SCOPED_TRACE(testing::Message() << "RoT payload: " << bin2hex(payload));
+
+        const auto [rot, rotPos, rotErrMsg] = cppbor::parse(payload);
+        ASSERT_TRUE(rot);
+        ASSERT_EQ(rot->semanticTagCount(), 1);
+        ASSERT_EQ(rot->semanticTag(), kRoTVersion1);
+        ASSERT_TRUE(rot->asArray());
+        ASSERT_EQ(rot->asArray()->size(), 5);
+
+        size_t pos = 0;
+
+        const auto& vbKey = rot->asArray()->get(pos++);
+        ASSERT_TRUE(vbKey);
+        ASSERT_TRUE(vbKey->asBstr());
+
+        const auto& deviceLocked = rot->asArray()->get(pos++);
+        ASSERT_TRUE(deviceLocked);
+        ASSERT_TRUE(deviceLocked->asBool());
+
+        const auto& verifiedBootState = rot->asArray()->get(pos++);
+        ASSERT_TRUE(verifiedBootState);
+        ASSERT_TRUE(verifiedBootState->asInt());
+
+        const auto& verifiedBootHash = rot->asArray()->get(pos++);
+        ASSERT_TRUE(verifiedBootHash);
+        ASSERT_TRUE(verifiedBootHash->asBstr());
+
+        const auto& bootPatchLevel = rot->asArray()->get(pos++);
+        ASSERT_TRUE(bootPatchLevel);
+        ASSERT_TRUE(bootPatchLevel->asInt());
+
+        verify_root_of_trust(vbKey->asBstr()->value(), deviceLocked->asBool()->value(),
+                             static_cast<VerifiedBoot>(verifiedBootState->asInt()->value()),
+                             verifiedBootHash->asBstr()->value());
+    }
+
     int32_t AidlVersion(shared_ptr<IKeyMintDevice> keymint) {
         int32_t version = 0;
         auto status = keymint->getInterfaceVersion(&version);
@@ -96,29 +175,19 @@
 
     vector<uint8_t> rootOfTrust1;
     Status result = tee->getRootOfTrust(challenge1, &rootOfTrust1);
-
-    // TODO: Remove the next line to require TEEs to succeed.
-    if (!result.isOk()) return;
-
-    ASSERT_TRUE(result.isOk());
-
-    // TODO:  Parse and validate rootOfTrust1 here
+    ASSERT_TRUE(result.isOk()) << "getRootOfTrust returned " << result.getServiceSpecificError();
+    validateMacedRootOfTrust(rootOfTrust1);
 
     vector<uint8_t> rootOfTrust2;
     result = tee->getRootOfTrust(challenge2, &rootOfTrust2);
     ASSERT_TRUE(result.isOk());
-
-    // TODO:  Parse and validate rootOfTrust2 here
-
+    validateMacedRootOfTrust(rootOfTrust2);
     ASSERT_NE(rootOfTrust1, rootOfTrust2);
 
     vector<uint8_t> rootOfTrust3;
     result = tee->getRootOfTrust(challenge1, &rootOfTrust3);
     ASSERT_TRUE(result.isOk());
-
     ASSERT_EQ(rootOfTrust1, rootOfTrust3);
-
-    // TODO:  Parse and validate rootOfTrust3 here
 }
 
 TEST_F(SecureElementProvisioningTest, TeeDoesNotImplementStrongBoxMethods) {
@@ -252,7 +321,7 @@
     result = tee->getRootOfTrust(challenge, &rootOfTrust);
     ASSERT_TRUE(result.isOk());
 
-    // TODO: Verify COSE_Mac0 structure and content here.
+    validateMacedRootOfTrust(rootOfTrust);
 
     result = sb->sendRootOfTrust(rootOfTrust);
     ASSERT_TRUE(result.isOk());
@@ -296,6 +365,8 @@
     result = tee->getRootOfTrust(challenge, &rootOfTrust);
     ASSERT_TRUE(result.isOk());
 
+    validateMacedRootOfTrust(rootOfTrust);
+
     vector<uint8_t> corruptedRootOfTrust = rootOfTrust;
     corruptedRootOfTrust[corruptedRootOfTrust.size() / 2]++;
     result = sb->sendRootOfTrust(corruptedRootOfTrust);
diff --git a/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp b/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
index 54b6fdc..5bbae4c 100644
--- a/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
+++ b/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
@@ -142,6 +142,25 @@
         return Digest::NONE;
     }
 
+    optional<EcCurve> getCurveFromLength(int keySize) {
+        switch (keySize) {
+            case 224:
+                return EcCurve::P_224;
+                break;
+            case 256:
+                return EcCurve::P_256;
+                break;
+            case 384:
+                return EcCurve::P_384;
+                break;
+            case 521:
+                return EcCurve::P_521;
+                break;
+            default:
+                return {};
+        }
+    }
+
     bool GenerateKey(string transform, int keySize, bool sign = false) {
         if (transform == key_transform_) {
             return true;
@@ -184,6 +203,12 @@
         }
         if (algorithm == Algorithm::EC) {
             authSet.SetDefaultValidity();
+            std::optional<EcCurve> curve = getCurveFromLength(keySize);
+            if (!curve) {
+                std::cerr << "Error: invalid EC-Curve from size " << keySize << std::endl;
+                return false;
+            }
+            authSet.Authorization(TAG_EC_CURVE, curve.value());
         }
         error_ = GenerateKey(authSet);
         return error_ == ErrorCode::OK;
diff --git a/security/secureclock/aidl/Android.bp b/security/secureclock/aidl/Android.bp
index 00a6ba3..853ad89 100644
--- a/security/secureclock/aidl/Android.bp
+++ b/security/secureclock/aidl/Android.bp
@@ -18,11 +18,6 @@
         java: {
             platform_apis: true,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
         rust: {
             enabled: true,
             apex_available: [
diff --git a/security/sharedsecret/aidl/Android.bp b/security/sharedsecret/aidl/Android.bp
index f1fce74..fe77c10 100644
--- a/security/sharedsecret/aidl/Android.bp
+++ b/security/sharedsecret/aidl/Android.bp
@@ -18,11 +18,6 @@
         java: {
             sdk_version: "module_current",
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
         rust: {
             enabled: true,
         },
diff --git a/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl b/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
index 8144699..b72f0de 100644
--- a/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
+++ b/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
@@ -33,9 +33,9 @@
     byte[] seed;
 
     /**
-     * A 32-byte value which is guaranteed to be different each time
-     * getSharedSecretParameters() is called.  Probabilistic uniqueness (i.e. random) is acceptable,
-     * though a stronger uniqueness guarantee (e.g. counter) is recommended where possible.
+     * A 32-byte value which is guaranteed to be different each time getSharedSecretParameters() is
+     * called after a restart.  Probabilistic uniqueness (i.e. random) is acceptable, though a
+     * stronger uniqueness guarantee (e.g. counter) is recommended where possible.
      */
     byte[] nonce;
 }
diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp
index 274cfa7..d53179a 100644
--- a/sensors/1.0/vts/functional/Android.bp
+++ b/sensors/1.0/vts/functional/Android.bp
@@ -26,7 +26,10 @@
 cc_test {
     name: "VtsHalSensorsV1_0TargetTest",
     cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
-    defaults: ["VtsHalTargetTestDefaults"],
+    defaults: [
+        "VtsHalSensorsDefaults",
+        "VtsHalTargetTestDefaults",
+    ],
     tidy_timeout_srcs: [
         "VtsHalSensorsV1_0TargetTest.cpp",
     ],
@@ -34,9 +37,12 @@
         "SensorsHidlEnvironmentV1_0.cpp",
         "VtsHalSensorsV1_0TargetTest.cpp",
     ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libvndksupport",
+    ],
     static_libs: [
         "android.hardware.sensors@1.0",
-        "VtsHalSensorsTargetTestUtils",
     ],
     test_suites: [
         "general-tests",
diff --git a/sensors/2.0/vts/functional/Android.bp b/sensors/2.0/vts/functional/Android.bp
index c4ec866..62eaf6b 100644
--- a/sensors/2.0/vts/functional/Android.bp
+++ b/sensors/2.0/vts/functional/Android.bp
@@ -26,7 +26,10 @@
 cc_test {
     name: "VtsHalSensorsV2_0TargetTest",
     cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
-    defaults: ["VtsHalTargetTestDefaults"],
+    defaults: [
+        "VtsHalSensorsDefaults",
+        "VtsHalTargetTestDefaults",
+    ],
     tidy_timeout_srcs: [
         "VtsHalSensorsV2_0TargetTest.cpp",
     ],
@@ -36,13 +39,15 @@
     header_libs: [
         "android.hardware.sensors@2.X-shared-utils",
     ],
+    shared_libs: [
+        "libbinder_ndk",
+    ],
     static_libs: [
         "android.hardware.sensors@1.0",
         "android.hardware.sensors@1.0-convert",
         "android.hardware.sensors@2.0",
         "android.hardware.sensors@2.1",
         "libfmq",
-        "VtsHalSensorsTargetTestUtils",
         "VtsHalSensorsV2_0TargetTest-lib",
     ],
     test_suites: [
diff --git a/sensors/2.1/vts/functional/Android.bp b/sensors/2.1/vts/functional/Android.bp
index 3659e11..61cfd14 100644
--- a/sensors/2.1/vts/functional/Android.bp
+++ b/sensors/2.1/vts/functional/Android.bp
@@ -28,7 +28,10 @@
     cflags: [
         "-DLOG_TAG=\"sensors_hidl_hal_test\"",
     ],
-    defaults: ["VtsHalTargetTestDefaults"],
+    defaults: [
+        "VtsHalSensorsDefaults",
+        "VtsHalTargetTestDefaults",
+    ],
     srcs: [
         "VtsHalSensorsV2_1TargetTest.cpp",
     ],
@@ -41,7 +44,6 @@
         "android.hardware.sensors@2.0",
         "android.hardware.sensors@2.1",
         "libfmq",
-        "VtsHalSensorsTargetTestUtils",
         "VtsHalSensorsV2_1TargetTest-lib",
     ],
     test_suites: [
diff --git a/sensors/aidl/Android.bp b/sensors/aidl/Android.bp
index 1c2d83f..d04017c 100644
--- a/sensors/aidl/Android.bp
+++ b/sensors/aidl/Android.bp
@@ -23,11 +23,6 @@
         java: {
             enabled: false,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
diff --git a/sensors/aidl/default/multihal/ConvertUtils.cpp b/sensors/aidl/default/multihal/ConvertUtils.cpp
index 9b2d8fe..bf56ed5 100644
--- a/sensors/aidl/default/multihal/ConvertUtils.cpp
+++ b/sensors/aidl/default/multihal/ConvertUtils.cpp
@@ -77,6 +77,8 @@
             hidlEvent->u.vec3.x = aidlEvent.payload.get<Event::EventPayload::vec3>().x;
             hidlEvent->u.vec3.y = aidlEvent.payload.get<Event::EventPayload::vec3>().y;
             hidlEvent->u.vec3.z = aidlEvent.payload.get<Event::EventPayload::vec3>().z;
+            hidlEvent->u.vec3.status =
+                    (V1_0SensorStatus)aidlEvent.payload.get<Event::EventPayload::vec3>().status;
             break;
         case AidlSensorType::GAME_ROTATION_VECTOR:
             hidlEvent->u.vec4.x = aidlEvent.payload.get<Event::EventPayload::vec4>().x;
@@ -225,6 +227,7 @@
             vec3.x = hidlEvent.u.vec3.x;
             vec3.y = hidlEvent.u.vec3.y;
             vec3.z = hidlEvent.u.vec3.z;
+            vec3.status = (SensorStatus)hidlEvent.u.vec3.status;
             aidlEvent->payload.set<Event::EventPayload::vec3>(vec3);
             break;
         }
diff --git a/sensors/aidl/vts/Android.bp b/sensors/aidl/vts/Android.bp
index b5a5f15..f3972ec 100644
--- a/sensors/aidl/vts/Android.bp
+++ b/sensors/aidl/vts/Android.bp
@@ -24,8 +24,9 @@
 cc_test {
     name: "VtsAidlHalSensorsTargetTest",
     defaults: [
-        "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
+        "VtsHalSensorsDefaults",
+        "VtsHalTargetTestDefaults",
     ],
     srcs: [
         "VtsAidlHalSensorsTargetTest.cpp",
diff --git a/sensors/common/vts/utils/Android.bp b/sensors/common/vts/utils/Android.bp
index 44bed6e..08b6afa 100644
--- a/sensors/common/vts/utils/Android.bp
+++ b/sensors/common/vts/utils/Android.bp
@@ -23,6 +23,23 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
+// Prefer to use these defaults to pull in VtsHalSensorsTargetTestUtils + its
+// dependencies
+cc_defaults {
+    name: "VtsHalSensorsDefaults",
+    shared_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
+        "android.hardware.graphics.common-V3-ndk",
+        "libbinder_ndk",
+        "libutils",
+        "libvndksupport",
+    ],
+    static_libs: [
+        "libaidlcommonsupport",
+        "VtsHalSensorsTargetTestUtils",
+    ],
+}
+
 cc_library_static {
     name: "VtsHalSensorsTargetTestUtils",
     defaults: ["VtsHalTargetTestDefaults"],
@@ -36,13 +53,19 @@
     local_include_dirs: [
         "include/sensors-vts-utils",
     ],
+    // Targets that depend on us need to also include these
     shared_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
+        "android.hardware.graphics.common-V3-ndk",
+        "libbinder_ndk",
         "libutils",
+        "libvndksupport",
     ],
     static_libs: [
         "android.hardware.sensors@1.0",
         "android.hardware.sensors@2.0",
         "android.hardware.sensors@2.1",
+        "libaidlcommonsupport",
     ],
     whole_static_libs: [
         "android.hardware.graphics.allocator@2.0",
diff --git a/sensors/common/vts/utils/GrallocWrapper.cpp b/sensors/common/vts/utils/GrallocWrapper.cpp
index 47d1f42..e6e0888 100644
--- a/sensors/common/vts/utils/GrallocWrapper.cpp
+++ b/sensors/common/vts/utils/GrallocWrapper.cpp
@@ -16,6 +16,9 @@
 
 #include "GrallocWrapper.h"
 
+#include <aidl/android/hardware/graphics/allocator/IAllocator.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android/binder_manager.h>
 #include <android/hardware/graphics/allocator/2.0/IAllocator.h>
 #include <android/hardware/graphics/allocator/3.0/IAllocator.h>
 #include <android/hardware/graphics/allocator/4.0/IAllocator.h>
@@ -27,8 +30,10 @@
 #include <utils/Log.h>
 
 #include <cinttypes>
+#include <memory>
 #include <type_traits>
 
+using IAllocatorAidl = ::aidl::android::hardware::graphics::allocator::IAllocator;
 using IAllocator2 = ::android::hardware::graphics::allocator::V2_0::IAllocator;
 using IAllocator3 = ::android::hardware::graphics::allocator::V3_0::IAllocator;
 using IAllocator4 = ::android::hardware::graphics::allocator::V4_0::IAllocator;
@@ -41,6 +46,9 @@
 using Error3 = ::android::hardware::graphics::mapper::V3_0::Error;
 using Error4 = ::android::hardware::graphics::mapper::V4_0::Error;
 
+using ::aidl::android::hardware::common::NativeHandle;
+using ::aidl::android::hardware::graphics::allocator::AllocationResult;
+
 using ::android::hardware::graphics::common::V1_0::BufferUsage;
 using ::android::hardware::graphics::common::V1_0::PixelFormat;
 
@@ -97,10 +105,11 @@
 
 // Since all the type and function names are the same for the things we use across the major HAL
 // versions, we use template magic to avoid repeating ourselves.
-template <typename AllocatorT, typename MapperT>
+template <typename AllocatorT, typename MapperT,
+          template <typename> typename AllocatorWrapperT = sp>
 class GrallocHalWrapper : public IGrallocHalWrapper {
   public:
-    GrallocHalWrapper(const sp<AllocatorT>& allocator, const sp<MapperT>& mapper)
+    GrallocHalWrapper(const AllocatorWrapperT<AllocatorT>& allocator, const sp<MapperT>& mapper)
         : mAllocator(allocator), mMapper(mapper) {
         if (mapper->isRemote()) {
             ALOGE("Mapper is in passthrough mode");
@@ -116,7 +125,7 @@
   private:
     static constexpr uint64_t kBufferUsage =
             static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::CPU_READ_OFTEN);
-    sp<AllocatorT> mAllocator;
+    AllocatorWrapperT<AllocatorT> mAllocator;
     sp<MapperT> mMapper;
 
     // v2.0 and v3.0 use vec<uint32_t> for BufferDescriptor, but v4.0 uses vec<uint8_t>, so use
@@ -128,8 +137,34 @@
     native_handle_t* importBuffer(const hidl_handle& rawHandle);
 };
 
-template <typename AllocatorT, typename MapperT>
-native_handle_t* GrallocHalWrapper<AllocatorT, MapperT>::allocate(uint32_t size) {
+template <>
+native_handle_t* GrallocHalWrapper<IAllocatorAidl, IMapper4, std::shared_ptr>::allocate(
+        uint32_t size) {
+    constexpr uint32_t kBufferCount = 1;
+    BufferDescriptorT descriptor = getDescriptor(size);
+    native_handle_t* bufferHandle = nullptr;
+
+    AllocationResult result;
+    auto status = mAllocator->allocate(descriptor, kBufferCount, &result);
+    if (!status.isOk()) {
+        status_t error = status.getExceptionCode();
+        ALOGE("Failed to allocate buffer: %" PRId32, static_cast<int32_t>(error));
+    } else if (result.buffers.size() != kBufferCount) {
+        ALOGE("Invalid buffer array size (got %zu, expected %" PRIu32 ")", result.buffers.size(),
+              kBufferCount);
+    } else {
+        // Convert from AIDL NativeHandle to native_handle_t to hidl_handle
+        hidl_handle hidlHandle;
+        hidlHandle.setTo(dupFromAidl(result.buffers[0]), /*shouldOwn*/ true);
+        bufferHandle = importBuffer(hidlHandle);
+    }
+
+    return bufferHandle;
+}
+
+template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT>
+native_handle_t* GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::allocate(
+        uint32_t size) {
     constexpr uint32_t kBufferCount = 1;
     BufferDescriptorT descriptor = getDescriptor(size);
     native_handle_t* bufferHandle = nullptr;
@@ -149,17 +184,18 @@
     return bufferHandle;
 }
 
-template <typename AllocatorT, typename MapperT>
-void GrallocHalWrapper<AllocatorT, MapperT>::freeBuffer(native_handle_t* bufferHandle) {
+template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT>
+void GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::freeBuffer(
+        native_handle_t* bufferHandle) {
     auto error = mMapper->freeBuffer(bufferHandle);
     if (!error.isOk() || failed(error)) {
         ALOGE("Failed to free buffer %p", bufferHandle);
     }
 }
 
-template <typename AllocatorT, typename MapperT>
-typename GrallocHalWrapper<AllocatorT, MapperT>::BufferDescriptorT
-GrallocHalWrapper<AllocatorT, MapperT>::getDescriptor(uint32_t size) {
+template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT>
+typename GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::BufferDescriptorT
+GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::getDescriptor(uint32_t size) {
     typename MapperT::BufferDescriptorInfo descriptorInfo = {
             .width = size,
             .height = 1,
@@ -181,8 +217,8 @@
     return descriptor;
 }
 
-template <typename AllocatorT, typename MapperT>
-native_handle_t* GrallocHalWrapper<AllocatorT, MapperT>::importBuffer(
+template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT>
+native_handle_t* GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::importBuffer(
         const hidl_handle& rawHandle) {
     native_handle_t* bufferHandle = nullptr;
 
@@ -198,8 +234,9 @@
     return bufferHandle;
 }
 
-template <typename AllocatorT, typename MapperT>
-void* GrallocHalWrapper<AllocatorT, MapperT>::lock(native_handle_t* bufferHandle) {
+template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT>
+void* GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::lock(
+        native_handle_t* bufferHandle) {
     // Per the HAL, all-zeros Rect means the entire buffer
     typename MapperT::Rect accessRegion = {};
     hidl_handle acquireFenceHandle;  // No fence needed, already safe to lock
@@ -218,8 +255,9 @@
     return data;
 }
 
-template <typename AllocatorT, typename MapperT>
-void GrallocHalWrapper<AllocatorT, MapperT>::unlock(native_handle_t* bufferHandle) {
+template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT>
+void GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::unlock(
+        native_handle_t* bufferHandle) {
     mMapper->unlock(bufferHandle, [&](auto error, const hidl_handle& /*releaseFence*/) {
         if (failed(error)) {
             ALOGE("Failed to unlock buffer %p: %" PRId32, bufferHandle,
@@ -234,8 +272,22 @@
     sp<IAllocator4> allocator4 = IAllocator4::getService();
     sp<IMapper4> mapper4 = IMapper4::getService();
 
-    if (allocator4 != nullptr && mapper4 != nullptr) {
-        ALOGD("Using IAllocator/IMapper v4.0");
+    const auto kAllocatorSvc = std::string(IAllocatorAidl::descriptor) + "/default";
+    std::shared_ptr<IAllocatorAidl> allocatorAidl;
+    if (AServiceManager_isDeclared(kAllocatorSvc.c_str())) {
+        allocatorAidl = IAllocatorAidl::fromBinder(
+                ndk::SpAIBinder(AServiceManager_checkService(kAllocatorSvc.c_str())));
+    }
+
+    // As of T, AIDL Allocator is supported only with HIDL Mapper4
+    // (ref: VtsHalGraphicsAllocatorAidl_TargetTest.cpp)
+    if (allocatorAidl != nullptr && mapper4 != nullptr) {
+        ALOGD("Using AIDL IAllocator + HIDL IMapper v4.0");
+        mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
+                new GrallocHalWrapper<IAllocatorAidl, IMapper4, std::shared_ptr>(allocatorAidl,
+                                                                                 mapper4));
+    } else if (allocator4 != nullptr && mapper4 != nullptr) {
+        ALOGD("AIDL IAllocator not found, using HIDL IAllocator/IMapper v4.0");
         mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
                 new GrallocHalWrapper<IAllocator4, IMapper4>(allocator4, mapper4));
     } else {
diff --git a/soundtrigger/aidl/Android.bp b/soundtrigger/aidl/Android.bp
index 448895c..0658519 100644
--- a/soundtrigger/aidl/Android.bp
+++ b/soundtrigger/aidl/Android.bp
@@ -33,11 +33,6 @@
         java: {
             sdk_version: "module_current",
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index 3e3a4d4..59b7939 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -144,9 +144,9 @@
     ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
     ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
     ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId, filterConf.getMqDesc));
-    mDvrTests.startPlaybackInputThread(dvrConf.playbackInputFile, dvrConf.settings.playback());
     ASSERT_TRUE(mDvrTests.startDvrPlayback());
     ASSERT_TRUE(mFilterTests.startFilter(filterId));
+    mDvrTests.startPlaybackInputThread(dvrConf.playbackInputFile, dvrConf.settings.playback());
     ASSERT_TRUE(filterDataOutputTest());
     mDvrTests.stopPlaybackThread();
     ASSERT_TRUE(mFilterTests.stopFilter(filterId));
diff --git a/tv/tuner/aidl/default/Filter.cpp b/tv/tuner/aidl/default/Filter.cpp
index 769ebe2..568ab07 100644
--- a/tv/tuner/aidl/default/Filter.cpp
+++ b/tv/tuner/aidl/default/Filter.cpp
@@ -432,12 +432,12 @@
 
     if (mSharedAvMemHandle != nullptr) {
         *out_avMemory = ::android::dupToAidl(mSharedAvMemHandle);
-        *_aidl_return = BUFFER_SIZE_16M;
+        *_aidl_return = BUFFER_SIZE;
         mUsingSharedAvMem = true;
         return ::ndk::ScopedAStatus::ok();
     }
 
-    int av_fd = createAvIonFd(BUFFER_SIZE_16M);
+    int av_fd = createAvIonFd(BUFFER_SIZE);
     if (av_fd < 0) {
         return ::ndk::ScopedAStatus::fromServiceSpecificError(
                 static_cast<int32_t>(Result::OUT_OF_MEMORY));
@@ -454,7 +454,7 @@
     mUsingSharedAvMem = true;
 
     *out_avMemory = ::android::dupToAidl(mSharedAvMemHandle);
-    *_aidl_return = BUFFER_SIZE_16M;
+    *_aidl_return = BUFFER_SIZE;
     return ::ndk::ScopedAStatus::ok();
 }
 
@@ -803,7 +803,7 @@
             }
         }
 
-        int endPoint = min(184, mPesSizeLeft);
+        uint32_t endPoint = min(184u, mPesSizeLeft);
         // append data and check size
         vector<int8_t>::const_iterator first = mFilterOutput.begin() + i + 4;
         vector<int8_t>::const_iterator last = mFilterOutput.begin() + i + 4 + endPoint;
@@ -885,7 +885,7 @@
             }
         }
 
-        int endPoint = min(184, mPesSizeLeft);
+        uint32_t endPoint = min(184u, mPesSizeLeft);
         // append data and check size
         vector<int8_t>::const_iterator first = mFilterOutput.begin() + i + 4;
         vector<int8_t>::const_iterator last = mFilterOutput.begin() + i + 4 + endPoint;
@@ -1168,7 +1168,7 @@
     mediaEvent.isPesPrivateData = true;
     mediaEvent.extraMetaData.set<DemuxFilterMediaEventExtraMetaData::Tag::audio>(audio);
 
-    int av_fd = createAvIonFd(BUFFER_SIZE_16M);
+    int av_fd = createAvIonFd(BUFFER_SIZE);
     if (av_fd == -1) {
         return;
     }
diff --git a/tv/tuner/aidl/default/Filter.h b/tv/tuner/aidl/default/Filter.h
index e301249..80faee7 100644
--- a/tv/tuner/aidl/default/Filter.h
+++ b/tv/tuner/aidl/default/Filter.h
@@ -50,7 +50,9 @@
 using ::android::hardware::EventFlag;
 
 using FilterMQ = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
-const uint32_t BUFFER_SIZE_16M = 0x1000000;
+// Large buffer size can lead to sudden crashes due to being de-allocated
+// by the memory management system. Change the buffer size when needed.
+const uint32_t BUFFER_SIZE = 0x800000;  // 8 MB
 
 class Demux;
 class Dvr;
@@ -258,7 +260,7 @@
 
     // temp handle single PES filter
     // TODO handle mulptiple Pes filters
-    int mPesSizeLeft = 0;
+    uint32_t mPesSizeLeft = 0;
     vector<int8_t> mPesOutput;
 
     // A map from data id to ion handle
diff --git a/tv/tuner/aidl/vts/functional/FrontendTests.cpp b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
index a1f51df..2ff0c3d 100644
--- a/tv/tuner/aidl/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-#include <aidl/android/hardware/tv/tuner/Result.h>
-
 #include "FrontendTests.h"
 
+#include <aidl/android/hardware/tv/tuner/Result.h>
+
 ndk::ScopedAStatus FrontendCallback::onEvent(FrontendEventType frontendEventType) {
     android::Mutex::Autolock autoLock(mMsgLock);
     ALOGD("[vts] frontend event received. Type: %d", frontendEventType);
@@ -323,7 +323,10 @@
         FrontendStatusType type = statusTypes[i];
         switch (type) {
             case FrontendStatusType::MODULATIONS: {
-                // TODO: verify modulations
+                ASSERT_TRUE(std::equal(
+                        realStatuses[i].get<FrontendStatus::Tag::modulations>().begin(),
+                        realStatuses[i].get<FrontendStatus::Tag::modulations>().end(),
+                        expectStatuses[i].get<FrontendStatus::Tag::modulations>().begin()));
                 break;
             }
             case FrontendStatusType::BERS: {
@@ -340,11 +343,13 @@
                 break;
             }
             case FrontendStatusType::GUARD_INTERVAL: {
-                // TODO: verify interval
+                ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::interval>() ==
+                            expectStatuses[i].get<FrontendStatus::Tag::interval>());
                 break;
             }
             case FrontendStatusType::TRANSMISSION_MODE: {
-                // TODO: verify tranmission mode
+                ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::transmissionMode>() ==
+                            expectStatuses[i].get<FrontendStatus::Tag::transmissionMode>());
                 break;
             }
             case FrontendStatusType::UEC: {
@@ -379,7 +384,8 @@
                 break;
             }
             case FrontendStatusType::ROLL_OFF: {
-                // TODO: verify roll off
+                ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::rollOff>() ==
+                            expectStatuses[i].get<FrontendStatus::Tag::rollOff>());
                 break;
             }
             case FrontendStatusType::IS_MISO: {
@@ -599,9 +605,10 @@
     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::ATSC3_ALL_PLP_INFO); i++) {
         allTypes.push_back(static_cast<FrontendStatusType>(i));
     }
+
     ndk::ScopedAStatus status = mFrontend->getFrontendStatusReadiness(allTypes, &readiness);
     ASSERT_TRUE(status.isOk());
     ASSERT_TRUE(readiness.size() == allTypes.size());
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
index 7f80d90..e8a7a79 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
@@ -36,6 +36,10 @@
     initFrontendConfig();
     initFilterConfig();
     initDvrConfig();
+    initTimeFilterConfig();
+    initDescramblerConfig();
+    initLnbConfig();
+    initDiseqcMsgsConfig();
     connectHardwaresToTestCases();
     if (!validateConnections()) {
         ALOGW("[vts] failed to validate connections.");
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
index 5f1f9c5..f093b8e 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
@@ -162,11 +162,36 @@
     TunerTestingConfigAidlReader1_0::readDvrConfig1_0(dvrMap);
 };
 
+inline void initTimeFilterConfig() {
+    // Read customized config
+    TunerTestingConfigAidlReader1_0::readTimeFilterConfig1_0(timeFilterMap);
+};
+
+inline void initDescramblerConfig() {
+    // Read customized config
+    TunerTestingConfigAidlReader1_0::readDescramblerConfig1_0(descramblerMap);
+}
+
+inline void initLnbConfig() {
+    // Read customized config
+    TunerTestingConfigAidlReader1_0::readLnbConfig1_0(lnbMap);
+};
+
+inline void initDiseqcMsgsConfig() {
+    // Read customized config
+    TunerTestingConfigAidlReader1_0::readDiseqcMessages(diseqcMsgMap);
+};
+
 /** Read the vendor configurations of which hardware to use for each test cases/data flows */
 inline void connectHardwaresToTestCases() {
     TunerTestingConfigAidlReader1_0::connectLiveBroadcast(live);
     TunerTestingConfigAidlReader1_0::connectScan(scan);
     TunerTestingConfigAidlReader1_0::connectDvrRecord(record);
+    TunerTestingConfigAidlReader1_0::connectTimeFilter(timeFilter);
+    TunerTestingConfigAidlReader1_0::connectDescrambling(descrambling);
+    TunerTestingConfigAidlReader1_0::connectLnbLive(lnbLive);
+    TunerTestingConfigAidlReader1_0::connectLnbRecord(lnbRecord);
+    TunerTestingConfigAidlReader1_0::connectDvrPlayback(playback);
 };
 
 inline bool validateConnections() {
@@ -183,6 +208,14 @@
     feIsValid &= record.support && record.hasFrontendConnection
                          ? frontendMap.find(record.frontendId) != frontendMap.end()
                          : true;
+    feIsValid &= descrambling.support && descrambling.hasFrontendConnection
+                         ? frontendMap.find(descrambling.frontendId) != frontendMap.end()
+                         : true;
+
+    feIsValid &= lnbLive.support ? frontendMap.find(lnbLive.frontendId) != frontendMap.end() : true;
+
+    feIsValid &=
+            lnbRecord.support ? frontendMap.find(lnbRecord.frontendId) != frontendMap.end() : true;
 
     if (!feIsValid) {
         ALOGW("[vts config] dynamic config fe connection is invalid.");
@@ -204,6 +237,20 @@
         dvrIsValid &= dvrMap.find(record.dvrRecordId) != dvrMap.end();
     }
 
+    if (descrambling.support) {
+        if (descrambling.hasFrontendConnection) {
+            if (frontendMap[descrambling.frontendId].isSoftwareFe) {
+                dvrIsValid &= dvrMap.find(descrambling.dvrSoftwareFeId) != dvrMap.end();
+            }
+        } else {
+            dvrIsValid &= dvrMap.find(descrambling.dvrSourceId) != dvrMap.end();
+        }
+    }
+
+    dvrIsValid &= lnbRecord.support ? dvrMap.find(lnbRecord.dvrRecordId) != dvrMap.end() : true;
+
+    dvrIsValid &= playback.support ? dvrMap.find(playback.dvrId) != dvrMap.end() : true;
+
     if (!dvrIsValid) {
         ALOGW("[vts config] dynamic config dvr connection is invalid.");
         return false;
@@ -216,10 +263,90 @@
     filterIsValid &=
             record.support ? filterMap.find(record.recordFilterId) != filterMap.end() : true;
 
+    filterIsValid &= descrambling.support
+                             ? filterMap.find(descrambling.videoFilterId) != filterMap.end() &&
+                                       filterMap.find(descrambling.audioFilterId) != filterMap.end()
+                             : true;
+
+    for (auto& filterId : descrambling.extraFilters) {
+        filterIsValid &= filterMap.find(filterId) != filterMap.end();
+    }
+
+    filterIsValid &= lnbLive.support
+                             ? filterMap.find(lnbLive.audioFilterId) != filterMap.end() &&
+                                       filterMap.find(lnbLive.videoFilterId) != filterMap.end()
+                             : true;
+
+    filterIsValid &=
+            lnbRecord.support ? filterMap.find(lnbRecord.recordFilterId) != filterMap.end() : true;
+
+    for (auto& filterId : lnbRecord.extraFilters) {
+        filterIsValid &= filterMap.find(filterId) != filterMap.end();
+    }
+
+    for (auto& filterId : lnbLive.extraFilters) {
+        filterIsValid &= filterMap.find(filterId) != filterMap.end();
+    }
+
+    filterIsValid &= playback.support
+                             ? filterMap.find(playback.audioFilterId) != filterMap.end() &&
+                                       filterMap.find(playback.videoFilterId) != filterMap.end()
+                             : true;
+    filterIsValid &= playback.sectionFilterId.compare(emptyHardwareId) == 0
+                             ? true
+                             : filterMap.find(playback.sectionFilterId) != filterMap.end();
+
+    for (auto& filterId : playback.extraFilters) {
+        filterIsValid &=
+                playback.hasExtraFilters ? filterMap.find(filterId) != filterMap.end() : true;
+    }
+
     if (!filterIsValid) {
         ALOGW("[vts config] dynamic config filter connection is invalid.");
         return false;
     }
 
+    bool timeFilterIsValid =
+            timeFilter.support ? timeFilterMap.find(timeFilter.timeFilterId) != timeFilterMap.end()
+                               : true;
+
+    if (!timeFilterIsValid) {
+        ALOGW("[vts config] dynamic config time filter connection is invalid.");
+    }
+
+    bool descramblerIsValid =
+            descrambling.support
+                    ? descramblerMap.find(descrambling.descramblerId) != descramblerMap.end()
+                    : true;
+
+    if (!descramblerIsValid) {
+        ALOGW("[vts config] dynamic config descrambler connection is invalid.");
+        return false;
+    }
+
+    bool lnbIsValid = lnbLive.support ? lnbMap.find(lnbLive.lnbId) != lnbMap.end() : true;
+
+    lnbIsValid &= lnbRecord.support ? lnbMap.find(lnbRecord.lnbId) != lnbMap.end() : true;
+
+    if (!lnbIsValid) {
+        ALOGW("[vts config] dynamic config lnb connection is invalid.");
+        return false;
+    }
+
+    bool diseqcMsgsIsValid = true;
+
+    for (auto& msg : lnbRecord.diseqcMsgs) {
+        diseqcMsgsIsValid &= diseqcMsgMap.find(msg) != diseqcMsgMap.end();
+    }
+
+    for (auto& msg : lnbLive.diseqcMsgs) {
+        diseqcMsgsIsValid &= diseqcMsgMap.find(msg) != diseqcMsgMap.end();
+    }
+
+    if (!diseqcMsgsIsValid) {
+        ALOGW("[vts config] dynamic config diseqcMsg is invalid.");
+        return false;
+    }
+
     return true;
 }
diff --git a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
index 189f5fd..b6e1020 100644
--- a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
+++ b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
@@ -146,12 +146,13 @@
 
 struct DvrPlaybackHardwareConnections {
     bool support;
+    bool hasExtraFilters = false;
     string frontendId;
     string dvrId;
     string audioFilterId;
     string videoFilterId;
     string sectionFilterId;
-    /* list string of extra filters; */
+    vector<string> extraFilters;
 };
 
 struct DvrRecordHardwareConnections {
@@ -173,7 +174,7 @@
     string videoFilterId;
     string descramblerId;
     string dvrSourceId;
-    /* list string of extra filters; */
+    vector<string> extraFilters;
 };
 
 struct LnbLiveHardwareConnections {
@@ -183,7 +184,7 @@
     string videoFilterId;
     string lnbId;
     vector<string> diseqcMsgs;
-    /* list string of extra filters; */
+    vector<string> extraFilters;
 };
 
 struct LnbRecordHardwareConnections {
@@ -193,7 +194,7 @@
     string recordFilterId;
     string lnbId;
     vector<string> diseqcMsgs;
-    /* list string of extra filters; */
+    vector<string> extraFilters;
 };
 
 struct TimeFilterHardwareConnections {
@@ -263,6 +264,9 @@
                         break;
                     case FrontendTypeEnum::ATSC:
                         type = FrontendType::ATSC;
+                        frontendMap[id].settings.set<
+                            FrontendSettings::Tag::atsc>(
+                                readAtscFrontendSettings(feConfig));
                         break;
                     case FrontendTypeEnum::ATSC3:
                         type = FrontendType::ATSC3;
@@ -283,12 +287,16 @@
                     }
                     case FrontendTypeEnum::ISDBS:
                         type = FrontendType::ISDBS;
+                        frontendMap[id].settings.set<FrontendSettings::Tag::isdbs>(
+                                readIsdbsFrontendSettings(feConfig));
                         break;
                     case FrontendTypeEnum::ISDBS3:
                         type = FrontendType::ISDBS3;
                         break;
                     case FrontendTypeEnum::ISDBT:
                         type = FrontendType::ISDBT;
+                        frontendMap[id].settings.set<FrontendSettings::Tag::isdbt>(
+                                readIsdbtFrontendSettings(feConfig));
                         break;
                     case FrontendTypeEnum::DTMB:
                         type = FrontendType::DTMB;
@@ -527,6 +535,13 @@
         } else {
             playback.sectionFilterId = emptyHardwareId;
         }
+        if (playbackConfig.hasOptionalFilters() && !playback.hasExtraFilters) {
+            auto optionalFilters = playbackConfig.getFirstOptionalFilters()->getOptionalFilter();
+            for (size_t i = 0; i < optionalFilters.size(); ++i) {
+                playback.extraFilters.push_back(optionalFilters[i].getFilterId());
+            }
+            playback.hasExtraFilters = true;
+        }
     }
 
     static void connectDvrRecord(DvrRecordHardwareConnections& record) {
@@ -576,6 +591,10 @@
             descrambling.hasFrontendConnection = false;
             descrambling.dvrSourceId = descConfig.getDvrSourceConnection();
         }
+        if (descConfig.hasOptionalFilters()) {
+            auto optionalFilters = descConfig.getOptionalFilters();
+            descrambling.extraFilters = optionalFilters;
+        }
     }
 
     static void connectLnbLive(LnbLiveHardwareConnections& lnbLive) {
@@ -596,6 +615,10 @@
                 lnbLive.diseqcMsgs.push_back(msgName);
             }
         }
+        if (lnbLiveConfig.hasOptionalFilters()) {
+            auto optionalFilters = lnbLiveConfig.getOptionalFilters();
+            lnbLive.extraFilters = optionalFilters;
+        }
     }
 
     static void connectLnbRecord(LnbRecordHardwareConnections& lnbRecord) {
@@ -616,6 +639,10 @@
                 lnbRecord.diseqcMsgs.push_back(msgName);
             }
         }
+        if (lnbRecordConfig.hasOptionalFilters()) {
+            auto optionalFilters = lnbRecordConfig.getOptionalFilters();
+            lnbRecord.extraFilters = optionalFilters;
+        }
     }
 
     static void connectTimeFilter(TimeFilterHardwareConnections& timeFilter) {
@@ -691,6 +718,82 @@
         return dvbsSettings;
     }
 
+    static FrontendAtscSettings readAtscFrontendSettings(Frontend& feConfig) {
+        ALOGW("[ConfigReader] fe type is atsc");
+        FrontendAtscSettings atscSettings{
+                .frequency = (int64_t)feConfig.getFrequency(),
+        };
+        if (feConfig.hasEndFrequency()) {
+            atscSettings.endFrequency = (int64_t)feConfig.getEndFrequency();
+        }
+        if (!feConfig.hasAtscFrontendSettings_optional()) {
+            ALOGW("[ConfigReader] no more atsc settings");
+            return atscSettings;
+        }
+        auto atsc = feConfig.getFirstAtscFrontendSettings_optional();
+        atscSettings.inversion = static_cast<FrontendSpectralInversion>(atsc->getInversion());
+        atscSettings.modulation = static_cast<FrontendAtscModulation>(atsc->getModulation());
+        return atscSettings;
+    }
+
+    static FrontendIsdbsSettings readIsdbsFrontendSettings(Frontend& feConfig) {
+        ALOGW("[ConfigReader] fe type is isdbs");
+        FrontendIsdbsSettings isdbsSettings{.frequency = (int64_t)feConfig.getFrequency()};
+        if (feConfig.hasEndFrequency()) {
+            isdbsSettings.endFrequency = (int64_t)feConfig.getEndFrequency();
+        }
+        if (!feConfig.hasIsdbsFrontendSettings_optional()) {
+            ALOGW("[ConfigReader] no more isdbs settings");
+            return isdbsSettings;
+        }
+        auto isdbs = feConfig.getFirstIsdbsFrontendSettings_optional();
+        isdbsSettings.streamId = (int32_t)isdbs->getStreamId();
+        isdbsSettings.symbolRate = (int32_t)isdbs->getSymbolRate();
+        isdbsSettings.modulation = static_cast<FrontendIsdbsModulation>(isdbs->getModulation());
+        isdbsSettings.coderate = static_cast<FrontendIsdbsCoderate>(isdbs->getCoderate());
+        isdbsSettings.rolloff = static_cast<FrontendIsdbsRolloff>(isdbs->getRolloff());
+        isdbsSettings.streamIdType =
+                static_cast<FrontendIsdbsStreamIdType>(isdbs->getStreamIdType());
+        return isdbsSettings;
+    }
+
+    static FrontendIsdbtSettings readIsdbtFrontendSettings(Frontend& feConfig) {
+        ALOGW("[ConfigReader] fe type is isdbt");
+        FrontendIsdbtSettings isdbtSettings{
+                .frequency = (int64_t)feConfig.getFrequency(),
+        };
+        if (feConfig.hasEndFrequency()) {
+            isdbtSettings.endFrequency = (int64_t)feConfig.getEndFrequency();
+        }
+        if (!feConfig.hasIsdbtFrontendSettings_optional()) {
+            ALOGW("[ConfigReader] no more isdbt settings");
+            return isdbtSettings;
+        }
+        auto isdbt = feConfig.getFirstIsdbtFrontendSettings_optional();
+        isdbtSettings.inversion = static_cast<FrontendSpectralInversion>(isdbt->getInversion());
+        isdbtSettings.bandwidth = static_cast<FrontendIsdbtBandwidth>(isdbt->getBandwidth());
+        isdbtSettings.mode = static_cast<FrontendIsdbtMode>(isdbt->getMode());
+        isdbtSettings.guardInterval =
+                static_cast<FrontendIsdbtGuardInterval>(isdbt->getGuardInterval());
+        isdbtSettings.serviceAreaId = (int32_t)isdbt->getServiceAreaId();
+        isdbtSettings.partialReceptionFlag =
+                static_cast<FrontendIsdbtPartialReceptionFlag>(isdbt->getPartialReceptionFlag());
+        if (!isdbt->hasFrontendIsdbtLayerSettings()) {
+            ALOGW("[ConfigReader] no isdbt layer settings");
+            return isdbtSettings;
+        }
+        auto layerSettings = isdbt->getFirstFrontendIsdbtLayerSettings();
+        ::aidl::android::hardware::tv::tuner::FrontendIsdbtLayerSettings mLayerSettings;
+        mLayerSettings.modulation =
+                static_cast<FrontendIsdbtModulation>(layerSettings->getModulation());
+        mLayerSettings.coderate = static_cast<FrontendIsdbtCoderate>(layerSettings->getCoderate());
+        mLayerSettings.timeInterleave =
+                static_cast<FrontendIsdbtTimeInterleaveMode>(layerSettings->getTimeInterleave());
+        mLayerSettings.numOfSegment = (int32_t)layerSettings->getNumOfSegment();
+        isdbtSettings.layerSettings.push_back(mLayerSettings);
+        return isdbtSettings;
+    }
+
     static bool readFilterTypeAndSettings(Filter filterConfig, DemuxFilterType& type,
                                           DemuxFilterSettings& settings) {
         auto mainType = filterConfig.getMainType();
diff --git a/tv/tuner/config/api/current.txt b/tv/tuner/config/api/current.txt
index 383d49f..9b500c3 100644
--- a/tv/tuner/config/api/current.txt
+++ b/tv/tuner/config/api/current.txt
@@ -1,6 +1,14 @@
 // Signature format: 2.0
 package android.media.tuner.testing.configuration.V1_0 {
 
+  public class AtscFrontendSettings {
+    ctor public AtscFrontendSettings();
+    method @Nullable public java.math.BigInteger getInversion();
+    method @Nullable public java.math.BigInteger getModulation();
+    method public void setInversion(@Nullable java.math.BigInteger);
+    method public void setModulation(@Nullable java.math.BigInteger);
+  }
+
   public class AvFilterSettings {
     ctor public AvFilterSettings();
     method @Nullable public short getAudioStreamType_optional();
@@ -59,6 +67,7 @@
     method @Nullable public String getDvrSourceConnection();
     method @Nullable public String getFrontendConnection();
     method @Nullable public boolean getHasFrontendConnection();
+    method @Nullable public java.util.List<java.lang.String> getOptionalFilters();
     method @Nullable public String getVideoFilterConnection();
     method public void setAudioFilterConnection(@Nullable String);
     method public void setDescramblerConnection(@Nullable String);
@@ -66,6 +75,7 @@
     method public void setDvrSourceConnection(@Nullable String);
     method public void setFrontendConnection(@Nullable String);
     method public void setHasFrontendConnection(@Nullable boolean);
+    method public void setOptionalFilters(@Nullable java.util.List<java.lang.String>);
     method public void setVideoFilterConnection(@Nullable String);
   }
 
@@ -73,14 +83,21 @@
     ctor public DataFlowConfiguration.DvrPlayback();
     method @Nullable public String getAudioFilterConnection();
     method @Nullable public String getDvrConnection();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.DvrPlayback.OptionalFilters getOptionalFilters();
     method @Nullable public String getSectionFilterConnection();
     method @Nullable public String getVideoFilterConnection();
     method public void setAudioFilterConnection(@Nullable String);
     method public void setDvrConnection(@Nullable String);
+    method public void setOptionalFilters(@Nullable android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.DvrPlayback.OptionalFilters);
     method public void setSectionFilterConnection(@Nullable String);
     method public void setVideoFilterConnection(@Nullable String);
   }
 
+  public static class DataFlowConfiguration.DvrPlayback.OptionalFilters {
+    ctor public DataFlowConfiguration.DvrPlayback.OptionalFilters();
+    method @Nullable public java.util.List<android.media.tuner.testing.configuration.V1_0.OptionalFilter> getOptionalFilter();
+  }
+
   public static class DataFlowConfiguration.DvrRecord {
     ctor public DataFlowConfiguration.DvrRecord();
     method @Nullable public String getDvrRecordConnection();
@@ -103,11 +120,13 @@
     method @Nullable public java.util.List<java.lang.String> getDiseqcMsgSender();
     method @Nullable public String getFrontendConnection();
     method @Nullable public String getLnbConnection();
+    method @Nullable public java.util.List<java.lang.String> getOptionalFilters();
     method @Nullable public String getVideoFilterConnection();
     method public void setAudioFilterConnection(@Nullable String);
     method public void setDiseqcMsgSender(@Nullable java.util.List<java.lang.String>);
     method public void setFrontendConnection(@Nullable String);
     method public void setLnbConnection(@Nullable String);
+    method public void setOptionalFilters(@Nullable java.util.List<java.lang.String>);
     method public void setVideoFilterConnection(@Nullable String);
   }
 
@@ -117,11 +136,13 @@
     method @Nullable public String getDvrRecordConnection();
     method @Nullable public String getFrontendConnection();
     method @Nullable public String getLnbConnection();
+    method @Nullable public java.util.List<java.lang.String> getOptionalFilters();
     method @Nullable public String getRecordFilterConnection();
     method public void setDiseqcMsgSender(@Nullable java.util.List<java.lang.String>);
     method public void setDvrRecordConnection(@Nullable String);
     method public void setFrontendConnection(@Nullable String);
     method public void setLnbConnection(@Nullable String);
+    method public void setOptionalFilters(@Nullable java.util.List<java.lang.String>);
     method public void setRecordFilterConnection(@Nullable String);
   }
 
@@ -310,6 +331,7 @@
 
   public class Frontend {
     ctor public Frontend();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.AtscFrontendSettings getAtscFrontendSettings_optional();
     method @Nullable public java.math.BigInteger getConnectToCicamId();
     method @Nullable public android.media.tuner.testing.configuration.V1_0.DvbsFrontendSettings getDvbsFrontendSettings_optional();
     method @Nullable public android.media.tuner.testing.configuration.V1_0.DvbtFrontendSettings getDvbtFrontendSettings_optional();
@@ -317,8 +339,11 @@
     method @Nullable public java.math.BigInteger getFrequency();
     method @Nullable public String getId();
     method @Nullable public boolean getIsSoftwareFrontend();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.IsdbsFrontendSettings getIsdbsFrontendSettings_optional();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.IsdbtFrontendSettings getIsdbtFrontendSettings_optional();
     method @Nullable public java.math.BigInteger getRemoveOutputPid();
     method @Nullable public android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum getType();
+    method public void setAtscFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.AtscFrontendSettings);
     method public void setConnectToCicamId(@Nullable java.math.BigInteger);
     method public void setDvbsFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.DvbsFrontendSettings);
     method public void setDvbtFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.DvbtFrontendSettings);
@@ -326,10 +351,24 @@
     method public void setFrequency(@Nullable java.math.BigInteger);
     method public void setId(@Nullable String);
     method public void setIsSoftwareFrontend(@Nullable boolean);
+    method public void setIsdbsFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.IsdbsFrontendSettings);
+    method public void setIsdbtFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.IsdbtFrontendSettings);
     method public void setRemoveOutputPid(@Nullable java.math.BigInteger);
     method public void setType(@Nullable android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum);
   }
 
+  public class FrontendIsdbtLayerSettings {
+    ctor public FrontendIsdbtLayerSettings();
+    method @Nullable public java.math.BigInteger getCoderate();
+    method @Nullable public java.math.BigInteger getModulation();
+    method @Nullable public java.math.BigInteger getNumOfSegment();
+    method @Nullable public java.math.BigInteger getTimeInterleave();
+    method public void setCoderate(@Nullable java.math.BigInteger);
+    method public void setModulation(@Nullable java.math.BigInteger);
+    method public void setNumOfSegment(@Nullable java.math.BigInteger);
+    method public void setTimeInterleave(@Nullable java.math.BigInteger);
+  }
+
   public enum FrontendTypeEnum {
     method @NonNull public String getRawName();
     enum_constant public static final android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum ANALOG;
@@ -422,6 +461,40 @@
     method public void setSrcPort(@Nullable long);
   }
 
+  public class IsdbsFrontendSettings {
+    ctor public IsdbsFrontendSettings();
+    method @Nullable public java.math.BigInteger getCoderate();
+    method @Nullable public java.math.BigInteger getModulation();
+    method @Nullable public java.math.BigInteger getRolloff();
+    method @Nullable public java.math.BigInteger getStreamId();
+    method @Nullable public java.math.BigInteger getStreamIdType();
+    method @Nullable public java.math.BigInteger getSymbolRate();
+    method public void setCoderate(@Nullable java.math.BigInteger);
+    method public void setModulation(@Nullable java.math.BigInteger);
+    method public void setRolloff(@Nullable java.math.BigInteger);
+    method public void setStreamId(@Nullable java.math.BigInteger);
+    method public void setStreamIdType(@Nullable java.math.BigInteger);
+    method public void setSymbolRate(@Nullable java.math.BigInteger);
+  }
+
+  public class IsdbtFrontendSettings {
+    ctor public IsdbtFrontendSettings();
+    method @Nullable public java.math.BigInteger getBandwidth();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.FrontendIsdbtLayerSettings getFrontendIsdbtLayerSettings();
+    method @Nullable public java.math.BigInteger getGuardInterval();
+    method @Nullable public java.math.BigInteger getInversion();
+    method @Nullable public java.math.BigInteger getMode();
+    method @Nullable public java.math.BigInteger getPartialReceptionFlag();
+    method @Nullable public java.math.BigInteger getServiceAreaId();
+    method public void setBandwidth(@Nullable java.math.BigInteger);
+    method public void setFrontendIsdbtLayerSettings(@Nullable android.media.tuner.testing.configuration.V1_0.FrontendIsdbtLayerSettings);
+    method public void setGuardInterval(@Nullable java.math.BigInteger);
+    method public void setInversion(@Nullable java.math.BigInteger);
+    method public void setMode(@Nullable java.math.BigInteger);
+    method public void setPartialReceptionFlag(@Nullable java.math.BigInteger);
+    method public void setServiceAreaId(@Nullable java.math.BigInteger);
+  }
+
   public class Lnb {
     ctor public Lnb();
     method @Nullable public String getId();
@@ -462,6 +535,12 @@
     enum_constant public static final android.media.tuner.testing.configuration.V1_0.LnbVoltageEnum VOLTAGE_5V;
   }
 
+  public class OptionalFilter {
+    ctor public OptionalFilter();
+    method @Nullable public String getFilterId();
+    method public void setFilterId(@Nullable String);
+  }
+
   public class RecordFilterSettings {
     ctor public RecordFilterSettings();
     method @Nullable public android.media.tuner.testing.configuration.V1_0.ScIndexTypeEnum getScIndexType();
diff --git a/tv/tuner/config/sample_tuner_vts_config_aidl_V1.xml b/tv/tuner/config/sample_tuner_vts_config_aidl_V1.xml
index fefe86e..90f3c9b 100644
--- a/tv/tuner/config/sample_tuner_vts_config_aidl_V1.xml
+++ b/tv/tuner/config/sample_tuner_vts_config_aidl_V1.xml
@@ -1,19 +1,15 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <!-- 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.
 -->
-
 <!-- The Sample Tuner Testing Configuration.
     Name the customized xml with "tuner_vts_config.xml" and push into the device
     "/vendor/etc" path. Please use "tuner_testing_dynamic_configuration.xsd" to verify the xml.
@@ -32,7 +28,6 @@
                 - The default settings can be found in the sample_tuner_vts_configurations.xml.
                 - The users can also override the default frontend settings using id="FE_DEFAULT".
                 - The users can configure 1 or more frontend elements in the frontends sections.
-
             Each frontend element contain the following attributes:
                 "id": unique id of the frontend that could be used to connect to the test the
                     "dataFlowConfiguration"
@@ -46,7 +41,6 @@
                     output. Supported in Tuner 2.0 or higher.
                 "frequency": the frequency used to configure tune and scan.
                 "endFrequency": the end frequency of scan. Supported in Tuner 1.1 or higher.
-
             Each frontend element also contains one and only one type-related "frontendSettings".
                 - The settings type should match the frontend "type" attribute.
                 - For example, when frontend type="DVBT", dvbtFrontendSettings can be configured.
@@ -54,14 +48,35 @@
                     config only to the hal.
         -->
         <frontends>
-            <frontend id="FE_DEFAULT" type="DVBT" isSoftwareFrontend="true"
+            <frontend id="FE_DEFAULT" type="ISDBS" isSoftwareFrontend="true"
                       connectToCicamId="0" removeOutputPid="10" frequency="578000000"
                       endFrequency="800000000">
-                <dvbtFrontendSettings bandwidth="8" transmissionMode="128" isHighPriority="1"/>
+              <isdbsFrontendSettings streamId="0" symbolRate="0" streamIdType="0" modulation="0" coderate="0" rolloff="0"/>
+            </frontend>
+            <frontend id="FE_ATSC_0" type="ATSC" isSoftwareFrontend="true"
+                      connectToCicamId="0" removeOutputPid="10" frequency="578000000"
+                      endFrequency="800000000">
+              <atscFrontendSettings inversion="0" modulation="0"/>
+            </frontend>
+            <frontend id="FE_ISDBT_0" type="ISDBT" isSoftwareFrontend="true"
+                      connectToCicamId="0" removeOutputPid="10" frequency="578000000"
+                      endFrequency="800000000">
+              <isdbtFrontendSettings serviceAreaId="0" inversion="0" bandwidth="0" mode="0" guardInterval="0" partialReceptionFlag="0">
+                <FrontendIsdbtLayerSettings modulation="0" coderate="0" timeInterleave="0" numOfSegment="0"/>
+              </isdbtFrontendSettings>
             </frontend>
             <frontend id="FE_DVBS_0" type="DVBS" isSoftwareFrontend="true"
                       connectToCicamId="0" removeOutputPid="10" frequency="578000000"
                       endFrequency="800000000">
+              <dvbsFrontendSettings inputStreamId="0" symbolRate="0"/>
+            </frontend>
+            <frontend id="FE_DVBT_0" type="DVBT" isSoftwareFrontend="true"
+                      connectToCicamId="0" removeOutputPid="10" frequency="578000000"
+                      endFrequency="800000000">
+              <dvbtFrontendSettings bandwidth="8" transmissionMode="1" isHighPriority="1"
+                                    constellation="1" hierarchy="1" hpCoderate="1" lpCoderate="1"
+                                    guardInterval="1" standard="1" isMiso="0" plpMode="1"
+                                    plpId="0" plpGroupId="0"/>
             </frontend>
         </frontends>
         <!-- Filter section:
@@ -71,7 +86,6 @@
                 - The users can also override the default filter settings using
                 - id="FILTER_AUDIO_DEFAULT" or "FILTER_VIDEO_DEFAULT".
                 - The users can configure 1 or more filter elements in the filters sections.
-
             Each filter element contain the following attributes:
                 "id": unique id of the filter that could be used to connect to the test the
                     "dataFlowConfiguration"
@@ -80,7 +94,6 @@
                 "bufferSize": the buffer size of the filter in hex.
                 "pid": the pid that would be used to configure the filter.
                 "useFMQ": if the filter uses FMQ.
-
             Each filter element also contains at most one type-related "filterSettings".
                 - The settings type should match the filter "subType" attribute.
                 - For example, when filter subType is audio or video, the avFilterSettings can be
@@ -89,6 +102,9 @@
                     only to the hal.
         -->
         <filters>
+            <filter id="FILTER_SECTION_DEFAULT" mainType="TS" subType="SECTION"
+              bufferSize="16777216" pid="257" useFMQ="false" monitorEventTypes="3">
+          </filter>
             <filter id="FILTER_AUDIO_DEFAULT" mainType="TS" subType="AUDIO"
                     bufferSize="16777216" pid="257" useFMQ="false" monitorEventTypes="3">
                 <avFilterSettings isPassthrough="false" isSecureMemory="false">
@@ -116,7 +132,6 @@
             This section contains configurations of all the dvrs that would be used in the tests.
                 - This section is optional and can be skipped if DVR is not supported.
                 - The users can configure 1 or more dvr elements in the dvrs sections.
-
             Each dvr element contain the following attributes:
                 "id": unique id of the dvr that could be used to connect to the test the
                     "dataFlowConfiguration"
@@ -140,8 +155,21 @@
                  statusMask="15" lowThreshold="4096" highThreshold="32767"
                  dataFormat="ES" packetSize="188" inputFilePath="/data/local/tmp/test.es"/>
         </dvrs>
+        <descramblers>
+            <descrambler id="DESCRAMBLER_0" casSystemId="63192"/>
+        </descramblers>
+        <timeFilters>
+            <timeFilter id="TIME_FILTER_0" timeStamp="1"/>
+        </timeFilters>
+        <diseqcMessages>
+            <diseqcMessage msgName="DISEQC_POWER_ON" msgBody="14 0 0 0 0 3"/>
+        </diseqcMessages>
+        <lnbs>
+            <lnb id="LNB_0" voltage="VOLTAGE_12V" tone="NONE" position="UNDEFINED"/>
+            <lnb id="LNB_1" name="default_lnb_external" voltage="VOLTAGE_5V"
+                            tone="NONE" position="UNDEFINED"/>
+        </lnbs>
     </hardwareConfiguration>
-
     <!-- Data flow configuration section connects each data flow under test to the ids of the
         hardwares that would be used during the tests. -->
     <dataFlowConfiguration>
@@ -151,13 +179,34 @@
                             ipFilterConnection="FILTER_IP_IP_0"
                             dvrSoftwareFeConnection="DVR_PLAYBACK_1"/>
         <scan frontendConnection="FE_DEFAULT"/>
-        <dvrPlayback dvrConnection="DVR_PLAYBACK_1"
-                     audioFilterConnection="FILTER_AUDIO_DEFAULT"
-                     videoFilterConnection="FILTER_VIDEO_DEFAULT"/>
         <dvrRecord hasFrontendConnection="true"
                    frontendConnection="FE_DEFAULT"
                    recordFilterConnection="FILTER_TS_RECORD_0"
                    dvrRecordConnection="DVR_RECORD_0"
                    dvrSoftwareFeConnection="DVR_PLAYBACK_1"/>
+        <dvrPlayback dvrConnection="DVR_PLAYBACK_1"
+                     audioFilterConnection="FILTER_AUDIO_DEFAULT"
+                     videoFilterConnection="FILTER_VIDEO_DEFAULT"
+                     sectionFilterConnection="FILTER_SECTION_DEFAULT"/>
+        <descrambling hasFrontendConnection="true"
+                      frontendConnection="FE_DEFAULT"
+                      descramblerConnection="DESCRAMBLER_0"
+                      audioFilterConnection="FILTER_AUDIO_DEFAULT"
+                      videoFilterConnection="FILTER_VIDEO_DEFAULT"
+                      dvrSoftwareFeConnection="DVR_PLAYBACK_0"
+                      dvrSourceConnection="DVR_PLAYBACK_1">
+                      <optionalFilters>FILTER_TS_RECORD_0 FILTER_IP_IP_0</optionalFilters>
+        </descrambling>
+        <timeFilter timeFilterConnection="TIME_FILTER_0"/>
+        <lnbLive frontendConnection="FE_DVBS_0"
+                 audioFilterConnection="FILTER_AUDIO_DEFAULT"
+                 videoFilterConnection="FILTER_VIDEO_DEFAULT"
+                 lnbConnection="LNB_1"
+                 diseqcMsgSender="DISEQC_POWER_ON"/>
+        <lnbRecord frontendConnection="FE_DVBS_0"
+                   recordFilterConnection="FILTER_TS_RECORD_0"
+                   dvrRecordConnection="DVR_RECORD_0"
+                   lnbConnection="LNB_0"
+                   diseqcMsgSender="DISEQC_POWER_ON"/>
     </dataFlowConfiguration>
 </TunerConfiguration>
diff --git a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
index 59abd9a..ee768ba 100644
--- a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
+++ b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
@@ -80,6 +80,33 @@
         <xs:attribute name="scanType" type="dvbsScanType" use="optional"/>
         <xs:attribute name="isDiseqcRxMessage" type="xs:boolean" use="optional"/>
     </xs:complexType>
+    <xs:complexType name="atscFrontendSettings">
+        <xs:attribute name="inversion" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="modulation" type="xs:nonNegativeInteger" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="isdbsFrontendSettings">
+        <xs:attribute name="streamId" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="symbolRate" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="streamIdType" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="modulation" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="coderate" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="rolloff" type="xs:nonNegativeInteger" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="isdbtFrontendSettings">
+        <xs:attribute name="serviceAreaId" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="inversion" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="bandwidth" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="mode" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="guardInterval" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="partialReceptionFlag" type="xs:nonNegativeInteger" use="required"/>
+        <xs:element name="FrontendIsdbtLayerSettings" type="FrontendIsdbtLayerSettings"/>
+    </xs:complexType>
+    <xs:complexType name="FrontendIsdbtLayerSettings">
+        <xs:attribute name="modulation" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="coderate" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="timeInterleave" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="numOfSegment" type="xs:nonNegativeInteger" use="required"/>
+    </xs:complexType>
 
     <xs:complexType name="frontend">
         <xs:annotation>
@@ -109,16 +136,16 @@
         </xs:annotation>
         <xs:choice minOccurs="0" maxOccurs="1">
             <!-- TODO: b/182519645 finish all the frontend settings structures. -->
-            <!--xs:element name="analog" type="analogSettings"/>
-            <xs:element name="atsc" type="atscSettings"/>
-            <xs:element name="atsc3" type="atsc3Settings"/>
+            <!--xs:element name="analog" type="analogSettings"/-->
+            <xs:element name="atscFrontendSettings" type="atscFrontendSettings"/>
+            <!--xs:element name="atsc3" type="atsc3Settings"/>
             <xs:element name="dvbc" type="dvbcSettings"/-->
             <xs:element name="dvbsFrontendSettings" type="dvbsFrontendSettings"/>
             <xs:element name="dvbtFrontendSettings" type="dvbtFrontendSettings"/>
-            <!--xs:element name="isdbs" type="isdbsSettings"/>
-            <xs:element name="isdbs3" type="isdbs3Settings"/>
-            <xs:element name="isdbt" type="isdbtSettings"/>
-            <xs:element name="dtmb" type="dtmbSettings"/-->
+            <xs:element name="isdbsFrontendSettings" type="isdbsFrontendSettings"/>
+            <!--xs:element name="isdbs3" type="isdbs3Settings"/-->
+            <xs:element name="isdbtFrontendSettings" type="isdbtFrontendSettings"/>
+            <!--xs:element name="dtmb" type="dtmbSettings"/-->
         </xs:choice>
         <xs:attribute name="id" type="frontendId" use="required"/>
         <xs:attribute name="type" type="frontendTypeEnum" use="required"/>
@@ -639,6 +666,7 @@
                     <xs:attribute name="audioFilterConnection" type="filterId" use="required"/>
                     <xs:attribute name="videoFilterConnection" type="filterId" use="required"/>
                     <!-- TODO: b/182519645 allow the users to insert extra filters -->
+                    <xs:element name="optionalFilters" type="filterConnections" minOccurs="0" maxOccurs="1"/>
                     <!-- This DVR is only required when the frontend is using the software input -->
                     <xs:attribute name="dvrSoftwareFeConnection" type="dvrId" use="optional"/>
                     <!-- This Dvr is only required when there's no frontend(sw or hw) connection -->
@@ -651,7 +679,14 @@
                     <xs:attribute name="audioFilterConnection" type="filterId" use="required"/>
                     <xs:attribute name="videoFilterConnection" type="filterId" use="required"/>
                     <xs:attribute name="sectionFilterConnection" type="filterId" use="optional"/>
-                    <!-- TODO: b/182519645 allow the users to insert extra filters -->
+                    <xs:element name="optionalFilters" minOccurs="0" maxOccurs="1">
+                      <xs:complexType>
+                          <xs:sequence>
+                            <xs:element name="optionalFilter" type="optionalFilter" minOccurs="1" maxOccurs="unbounded"/>
+                          </xs:sequence>
+                      </xs:complexType>
+                    </xs:element>
+                    <!--TODO: b/182519645 allow the users to insert extra filters/-->
                 </xs:complexType>
             </xs:element>
             <xs:element name="dvrRecord" minOccurs="0" maxOccurs="1">
@@ -675,7 +710,7 @@
                     <xs:attribute name="videoFilterConnection" type="filterId" use="required"/>
                     <xs:attribute name="lnbConnection" type="lnbId" use="required"/>
                     <xs:attribute name="diseqcMsgSender" type="diseqcMsgSender" use="optional"/>
-                    <!-- TODO: b/182519645 allow the users to insert extra filters -->
+                    <xs:element name="optionalFilters" type="filterConnections" minOccurs="0" maxOccurs="1"/>
                 </xs:complexType>
             </xs:element>
             <xs:element name="lnbRecord" minOccurs="0" maxOccurs="1">
@@ -685,6 +720,7 @@
                     <xs:attribute name="dvrRecordConnection" type="dvrId" use="required"/>
                     <xs:attribute name="lnbConnection" type="lnbId" use="required"/>
                     <xs:attribute name="diseqcMsgSender" type="diseqcMsgSender" use="optional"/>
+                    <xs:element name="optionalFilters" type="filterConnections" minOccurs="0" maxOccurs="1"/>
                 </xs:complexType>
             </xs:element>
             <xs:element name="timeFilter" minOccurs="0" maxOccurs="1">
@@ -729,4 +765,7 @@
             <xs:field xpath="@id"/>
         </xs:key>
     </xs:element>
+    <xs:complexType name="optionalFilter">
+        <xs:attribute name="filterId" type="filterId" use="required"/>
+    </xs:complexType>
 </xs:schema>
diff --git a/usb/aidl/Android.bp b/usb/aidl/Android.bp
index 7eb6020..4f59f02 100644
--- a/usb/aidl/Android.bp
+++ b/usb/aidl/Android.bp
@@ -33,11 +33,6 @@
         java: {
             sdk_version: "module_current",
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions_with_info: [
         {
diff --git a/uwb/aidl/Android.bp b/uwb/aidl/Android.bp
index cc61046..7dc2b7f 100755
--- a/uwb/aidl/Android.bp
+++ b/uwb/aidl/Android.bp
@@ -21,9 +21,6 @@
             enabled: false,
         },
         ndk: {
-            vndk: {
-                enabled: true,
-            },
             apex_available: [
                 "//apex_available:platform",
                 "com.android.uwb",
@@ -50,6 +47,7 @@
 
 aidl_interface {
     name: "android.hardware.uwb.fira_android",
+    owner: "google",
     vendor_available: true,
     srcs: ["android/hardware/uwb/fira_android/*.aidl"],
     stability: "vintf",
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index cbe2068..cd08671 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -44,4 +44,7 @@
   CCC_SUPPORTED_PULSE_SHAPE_COMBOS = 166,
   CCC_SUPPORTED_RAN_MULTIPLIER = 167,
   SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 227,
+  SUPPORTED_MIN_RANGING_INTERVAL_MS = 228,
+  SUPPORTED_RANGE_DATA_NTF_CONFIG = 229,
+  SUPPORTED_RSSI_REPORTING = 230,
 }
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index 0140fdd..556bd13 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -150,4 +150,25 @@
      *  0 - Feature not supported.
      */
     SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 0xE3,
+
+    /**
+     * 4 byte value to indicate supported min ranging interval in ms.
+     */
+    SUPPORTED_MIN_RANGING_INTERVAL_MS = 0xE4,
+
+    /**
+     * 4 byte bitmask to indicate the supported RANGE_DATA_NTF_CONFIG values
+     *
+     * Bitmask where each bit corresponds to values used in
+     * RANGE_DATA_NTF_CONFIG in SET_APP_CFG_CMD
+     */
+    SUPPORTED_RANGE_DATA_NTF_CONFIG = 0xE5,
+
+    /**
+     * 1 byte bitmask to indicate the supported RSSI_REPORTING values
+     * Values:
+     * 1 - Feature supported.
+     * 0 - Feature not supported.
+     */
+    SUPPORTED_RSSI_REPORTING = 0xE6,
 }
diff --git a/uwb/aidl/vts/VtsHalUwbTargetTest.cpp b/uwb/aidl/vts/VtsHalUwbTargetTest.cpp
index edd8dd6..81d26ba 100644
--- a/uwb/aidl/vts/VtsHalUwbTargetTest.cpp
+++ b/uwb/aidl/vts/VtsHalUwbTargetTest.cpp
@@ -68,6 +68,11 @@
         iuwb_ = IUwb::fromBinder(SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
         ASSERT_NE(iuwb_, nullptr);
     }
+    virtual void TearDown() override {
+        // Trigger HAL close at end of each test.
+        const auto iuwb_chip = getAnyChip();
+        iuwb_chip->close();
+    }
     std::shared_ptr<IUwb> iuwb_;
 
     // TODO (b/197638976): We pick the first chip here. Need to fix this
diff --git a/vibrator/aidl/Android.bp b/vibrator/aidl/Android.bp
index d4d5857..86ef027 100644
--- a/vibrator/aidl/Android.bp
+++ b/vibrator/aidl/Android.bp
@@ -19,11 +19,6 @@
         java: {
             sdk_version: "module_current",
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions: [
         "1",
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index ddc6ee0..01602ab 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -59,7 +59,10 @@
                                 const std::shared_ptr<IVibratorCallback>& callback) {
     LOG(VERBOSE) << "Vibrator on for timeoutMs: " << timeoutMs;
     if (callback != nullptr) {
-        std::thread([=] {
+        // 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";
@@ -87,7 +90,7 @@
     constexpr size_t kEffectMillis = 100;
 
     if (callback != nullptr) {
-        std::thread([=] {
+        std::thread([callback] {
             LOG(VERBOSE) << "Starting perform on another thread";
             usleep(kEffectMillis * 1000);
             LOG(VERBOSE) << "Notifying perform complete";
@@ -174,7 +177,8 @@
         }
     }
 
-    std::thread([=] {
+    // 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";
 
         for (auto& e : composite) {
@@ -185,7 +189,7 @@
                          << e.scale;
 
             int32_t durationMs;
-            getPrimitiveDuration(e.primitive, &durationMs);
+            sharedThis->getPrimitiveDuration(e.primitive, &durationMs);
             usleep(durationMs * 1000);
         }
 
@@ -396,7 +400,7 @@
         }
     }
 
-    std::thread([=] {
+    std::thread([totalDuration, callback] {
         LOG(VERBOSE) << "Starting composePwle on another thread";
         usleep(totalDuration * 1000);
         if (callback != nullptr) {
diff --git a/vibrator/aidl/default/VibratorManager.cpp b/vibrator/aidl/default/VibratorManager.cpp
index 7cf9e6a..26edf5a 100644
--- a/vibrator/aidl/default/VibratorManager.cpp
+++ b/vibrator/aidl/default/VibratorManager.cpp
@@ -66,7 +66,7 @@
 ndk::ScopedAStatus VibratorManager::triggerSynced(
         const std::shared_ptr<IVibratorCallback>& callback) {
     LOG(INFO) << "Vibrator Manager trigger synced";
-    std::thread([=] {
+    std::thread([callback] {
         if (callback != nullptr) {
             LOG(INFO) << "Notifying perform complete";
             callback->onComplete();
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index 3841715..791d7e8 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -332,6 +332,7 @@
         sleep(1);
         EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(1.0f).exceptionCode());
         sleep(1);
+        EXPECT_TRUE(vibrator->off().isOk());
     }
 }
 
diff --git a/weaver/aidl/Android.bp b/weaver/aidl/Android.bp
index 8b4306f..caa92aa 100644
--- a/weaver/aidl/Android.bp
+++ b/weaver/aidl/Android.bp
@@ -16,11 +16,6 @@
         java: {
             platform_apis: true,
         },
-        ndk: {
-            vndk: {
-                enabled: true,
-            },
-        },
     },
     versions: ["1"],
 }
diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp
index f86869b..cac8c0b 100644
--- a/wifi/1.4/vts/functional/Android.bp
+++ b/wifi/1.4/vts/functional/Android.bp
@@ -44,6 +44,27 @@
     ],
 }
 
+cc_library_static {
+    name: "VtsHalWifiV1_4TargetTestUtil",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "wifi_hidl_test_utils_1_4.cpp",
+    ],
+    export_include_dirs: [
+        ".",
+    ],
+    shared_libs: [
+        "libnativehelper",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+        "libwifi-system-iface",
+    ],
+}
+
 // SoftAP-specific tests, similar to VtsHalWifiApV1_0TargetTest.
 cc_test {
     name: "VtsHalWifiApV1_4TargetTest",
diff --git a/wifi/1.4/vts/functional/wifi_hidl_test_utils_1_4.cpp b/wifi/1.4/vts/functional/wifi_hidl_test_utils_1_4.cpp
new file mode 100644
index 0000000..02e8320
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_hidl_test_utils_1_4.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/logging.h>
+
+#undef NAN  // NAN is defined in bionic/libc/include/math.h:38
+
+#include <android/hardware/wifi/1.4/IWifi.h>
+#include <android/hardware/wifi/1.4/IWifiApIface.h>
+#include <android/hardware/wifi/1.4/IWifiChip.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "wifi_hidl_call_util.h"
+#include "wifi_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::V1_0::ChipModeId;
+using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_4::IWifiApIface;
+using ::android::hardware::wifi::V1_4::IWifiChip;
+
+sp<IWifiChip> getWifiChip_1_4(const std::string& instance_name) {
+    return IWifiChip::castFrom(getWifiChip(instance_name));
+}
+
+sp<IWifiApIface> getWifiApIface_1_4(const std::string& instance_name) {
+    LOG(INFO) << "getWifiApIface_1_4";
+    ChipModeId mode_id;
+    sp<IWifiChip> wifi_chip_ = getWifiChip_1_4(instance_name);
+    configureChipToSupportIfaceType(wifi_chip_, IfaceType::AP, &mode_id);
+    const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createApIface);
+    LOG(INFO) << "getWifiApIface_1_4 done to status_and_iface";
+    return IWifiApIface::castFrom(status_and_iface.second);
+}
diff --git a/wifi/1.4/vts/functional/wifi_hidl_test_utils_1_4.h b/wifi/1.4/vts/functional/wifi_hidl_test_utils_1_4.h
new file mode 100644
index 0000000..ca7b57a
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_hidl_test_utils_1_4.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/wifi/1.4/IWifi.h>
+#include <android/hardware/wifi/1.4/IWifiApIface.h>
+#include <android/hardware/wifi/1.4/IWifiChip.h>
+
+#include <getopt.h>
+
+#include <VtsHalHidlTargetTestEnvBase.h>
+// Helper functions to obtain references to the various HIDL interface objects.
+// Note: We only have a single instance of each of these objects currently.
+// These helper functions should be modified to return vectors if we support
+// multiple instances.
+android::sp<android::hardware::wifi::V1_4::IWifiChip> getWifiChip_1_4(
+    const std::string& instance_name);
+android::sp<android::hardware::wifi::V1_4::IWifiApIface> getWifiApIface_1_4(
+    const std::string& instance_name);
diff --git a/wifi/1.6/default/ringbuffer.cpp b/wifi/1.6/default/ringbuffer.cpp
index 6d4ed84..981bf7b 100644
--- a/wifi/1.6/default/ringbuffer.cpp
+++ b/wifi/1.6/default/ringbuffer.cpp
@@ -26,20 +26,26 @@
 
 Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {}
 
-void Ringbuffer::append(const std::vector<uint8_t>& input) {
+enum Ringbuffer::AppendStatus Ringbuffer::append(const std::vector<uint8_t>& input) {
     if (input.size() == 0) {
-        return;
+        return AppendStatus::FAIL_IP_BUFFER_ZERO;
     }
     if (input.size() > maxSize_) {
         LOG(INFO) << "Oversized message of " << input.size() << " bytes is dropped";
-        return;
+        return AppendStatus::FAIL_IP_BUFFER_EXCEEDED_MAXSIZE;
     }
     data_.push_back(input);
     size_ += input.size() * sizeof(input[0]);
     while (size_ > maxSize_) {
+        if (data_.front().size() <= 0 || data_.front().size() > maxSize_) {
+            LOG(ERROR) << "First buffer in the ring buffer is Invalid. Size: "
+                       << data_.front().size();
+            return AppendStatus::FAIL_RING_BUFFER_CORRUPTED;
+        }
         size_ -= data_.front().size() * sizeof(data_.front()[0]);
         data_.pop_front();
     }
+    return AppendStatus::SUCCESS;
 }
 
 const std::list<std::vector<uint8_t>>& Ringbuffer::getData() const {
diff --git a/wifi/1.6/default/ringbuffer.h b/wifi/1.6/default/ringbuffer.h
index 8571a9f..c6a1e4c 100644
--- a/wifi/1.6/default/ringbuffer.h
+++ b/wifi/1.6/default/ringbuffer.h
@@ -31,11 +31,19 @@
  */
 class Ringbuffer {
   public:
+    // Error codes for the append ring buffer operation
+    enum AppendStatus {
+        SUCCESS,
+        FAIL_GENERIC,
+        FAIL_IP_BUFFER_ZERO,
+        FAIL_IP_BUFFER_EXCEEDED_MAXSIZE,
+        FAIL_RING_BUFFER_CORRUPTED
+    };
     explicit Ringbuffer(size_t maxSize);
 
     // Appends the data buffer and deletes from the front until buffer is
     // within |maxSize_|.
-    void append(const std::vector<uint8_t>& input);
+    enum AppendStatus append(const std::vector<uint8_t>& input);
     const std::list<std::vector<uint8_t>>& getData() const;
     void clear();
 
diff --git a/wifi/1.6/default/wifi_chip.cpp b/wifi/1.6/default/wifi_chip.cpp
index f062409..c7c00b1 100644
--- a/wifi/1.6/default/wifi_chip.cpp
+++ b/wifi/1.6/default/wifi_chip.cpp
@@ -1613,6 +1613,7 @@
                     return;
                 }
                 WifiDebugRingBufferStatus hidl_status;
+                Ringbuffer::AppendStatus appendstatus;
                 if (!hidl_struct_util::convertLegacyDebugRingBufferStatusToHidl(status,
                                                                                 &hidl_status)) {
                     LOG(ERROR) << "Error converting ring buffer status";
@@ -1623,13 +1624,19 @@
                     const auto& target = shared_ptr_this->ringbuffer_map_.find(name);
                     if (target != shared_ptr_this->ringbuffer_map_.end()) {
                         Ringbuffer& cur_buffer = target->second;
-                        cur_buffer.append(data);
+                        appendstatus = cur_buffer.append(data);
                     } else {
                         LOG(ERROR) << "Ringname " << name << " not found";
                         return;
                     }
                     // unique_lock unlocked here
                 }
+                if (appendstatus == Ringbuffer::AppendStatus::FAIL_RING_BUFFER_CORRUPTED) {
+                    LOG(ERROR) << "Ringname " << name << " is corrupted. Clear the ring buffer";
+                    shared_ptr_this->writeRingbufferFilesInternal();
+                    return;
+                }
+
             };
     legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->registerRingBufferCallbackHandler(
             getFirstActiveWlanIfaceName(), on_ring_buffer_data_callback);
@@ -1971,6 +1978,11 @@
             }
             unique_fd file_auto_closer(dump_fd);
             for (const auto& cur_block : cur_buffer.getData()) {
+                if (cur_block.size() <= 0 || cur_block.size() > kMaxBufferSizeBytes) {
+                    PLOG(ERROR) << "Ring buffer: " << item.first
+                                << " is corrupted. Invalid block size: " << cur_block.size();
+                    break;
+                }
                 if (write(dump_fd, cur_block.data(), sizeof(cur_block[0]) * cur_block.size()) ==
                     -1) {
                     PLOG(ERROR) << "Error writing to file";
diff --git a/wifi/hostapd/1.2/vts/functional/Android.bp b/wifi/hostapd/1.2/vts/functional/Android.bp
index 9609da5..26edab5 100644
--- a/wifi/hostapd/1.2/vts/functional/Android.bp
+++ b/wifi/hostapd/1.2/vts/functional/Android.bp
@@ -31,12 +31,17 @@
     ],
     static_libs: [
         "VtsHalWifiV1_0TargetTestUtil",
+        "VtsHalWifiV1_4TargetTestUtil",
         "VtsHalWifiHostapdV1_0TargetTestUtil",
         "android.hardware.wifi.hostapd@1.0",
         "android.hardware.wifi.hostapd@1.1",
         "android.hardware.wifi.hostapd@1.2",
         "android.hardware.wifi.hostapd@1.3",
         "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
         "libgmock",
         "libwifi-system",
         "libwifi-system-iface",
diff --git a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
index c40c582..5c59819 100644
--- a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
@@ -29,6 +29,7 @@
 
 #include "hostapd_hidl_call_util.h"
 #include "hostapd_hidl_test_utils.h"
+#include "wifi_hidl_test_utils_1_4.h"
 
 using ::android::sp;
 using ::android::hardware::hidl_string;
@@ -39,6 +40,9 @@
 using ::android::hardware::wifi::hostapd::V1_2::Ieee80211ReasonCode;
 using ::android::hardware::wifi::hostapd::V1_2::IHostapd;
 using ::android::hardware::wifi::V1_0::IWifi;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_4::IWifiApIface;
+using ::android::hardware::wifi::V1_4::IWifiChip;
 
 namespace {
 constexpr unsigned char kNwSsid[] = {'t', 'e', 's', 't', '1',
@@ -81,23 +85,25 @@
    protected:
     bool isWpa3SaeSupport_ = false;
     bool isAcsSupport_ = false;
-    std::string getPrimaryWlanIfaceName() {
-        std::array<char, PROPERTY_VALUE_MAX> buffer;
-        auto res = property_get("ro.vendor.wifi.sap.interface", buffer.data(),
-                                nullptr);
-        if (res > 0) return buffer.data();
-        property_get("wifi.interface", buffer.data(), "wlan0");
-        return buffer.data();
+
+    std::string setupApIfaceIfNeededAndGetName() {
+        sp<IWifiApIface> wifi_ap_iface;
+        wifi_ap_iface = getWifiApIface_1_4(wifi_instance_name_);
+        EXPECT_NE(nullptr, wifi_ap_iface.get());
+
+        const auto& status_and_name = HIDL_INVOKE(wifi_ap_iface, getName);
+        EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_name.first.code);
+        return status_and_name.second;
     }
 
-    IHostapd::IfaceParams getIfaceParamsWithoutAcs() {
+    IHostapd::IfaceParams getIfaceParamsWithoutAcs(std::string iface_name) {
         ::android::hardware::wifi::hostapd::V1_0::IHostapd::IfaceParams
             iface_params;
         ::android::hardware::wifi::hostapd::V1_1::IHostapd::IfaceParams
             iface_params_1_1;
         IHostapd::IfaceParams iface_params_1_2;
 
-        iface_params.ifaceName = getPrimaryWlanIfaceName();
+        iface_params.ifaceName = iface_name;
         iface_params.hwModeParams.enable80211N = true;
         iface_params.hwModeParams.enable80211AC = false;
         iface_params.channelParams.enableAcs = false;
@@ -114,9 +120,10 @@
         return iface_params_1_2;
     }
 
-    IHostapd::IfaceParams getIfaceParamsWithAcs() {
+    IHostapd::IfaceParams getIfaceParamsWithAcs(std::string iface_name) {
         // First get the settings for WithoutAcs and then make changes
-        IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithoutAcs();
+        IHostapd::IfaceParams iface_params_1_2 =
+            getIfaceParamsWithoutAcs(iface_name);
         iface_params_1_2.V1_1.V1_0.channelParams.enableAcs = true;
         iface_params_1_2.V1_1.V1_0.channelParams.acsShouldExcludeDfs = true;
         iface_params_1_2.V1_1.V1_0.channelParams.channel = 0;
@@ -126,8 +133,10 @@
         return iface_params_1_2;
     }
 
-    IHostapd::IfaceParams getIfaceParamsWithAcsAndFreqRange() {
-        IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithAcs();
+    IHostapd::IfaceParams getIfaceParamsWithAcsAndFreqRange(
+        std::string iface_name) {
+        IHostapd::IfaceParams iface_params_1_2 =
+            getIfaceParamsWithAcs(iface_name);
         ::android::hardware::wifi::hostapd::V1_2::IHostapd::AcsFrequencyRange
             acsFrequencyRange;
         acsFrequencyRange.start = 2412;
@@ -141,9 +150,10 @@
         return iface_params_1_2;
     }
 
-    IHostapd::IfaceParams getIfaceParamsWithAcsAndInvalidFreqRange() {
+    IHostapd::IfaceParams getIfaceParamsWithAcsAndInvalidFreqRange(
+        std::string iface_name) {
         IHostapd::IfaceParams iface_params_1_2 =
-            getIfaceParamsWithAcsAndFreqRange();
+            getIfaceParamsWithAcsAndFreqRange(iface_name);
         iface_params_1_2.channelParams.acsChannelFreqRangesMhz[0].start = 222;
         iface_params_1_2.channelParams.acsChannelFreqRangesMhz[0].end = 999;
         return iface_params_1_2;
@@ -205,8 +215,10 @@
         return nw_params_1_2;
     }
 
-    IHostapd::IfaceParams getIfaceParamsWithInvalidChannel() {
-        IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithoutAcs();
+    IHostapd::IfaceParams getIfaceParamsWithInvalidChannel(
+        std::string iface_name) {
+        IHostapd::IfaceParams iface_params_1_2 =
+            getIfaceParamsWithoutAcs(iface_name);
         iface_params_1_2.V1_1.V1_0.channelParams.channel = kIfaceInvalidChannel;
         return iface_params_1_2;
     }
@@ -231,8 +243,9 @@
     if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
     if (is_1_3(hostapd_))
         GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
+    std::string ifname = setupApIfaceIfNeededAndGetName();
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
-                              getIfaceParamsWithAcs(), getPskNwParams());
+                              getIfaceParamsWithAcs(ifname), getPskNwParams());
     EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
 }
 
@@ -244,9 +257,10 @@
     if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
     if (is_1_3(hostapd_))
         GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
-    auto status =
-        HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
-                    getIfaceParamsWithAcsAndFreqRange(), getPskNwParams());
+    std::string ifname = setupApIfaceIfNeededAndGetName();
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                              getIfaceParamsWithAcsAndFreqRange(ifname),
+                              getPskNwParams());
     EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
 }
 
@@ -258,8 +272,9 @@
     if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
     if (is_1_3(hostapd_))
         GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
+    std::string ifname = setupApIfaceIfNeededAndGetName();
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
-                              getIfaceParamsWithAcsAndInvalidFreqRange(),
+                              getIfaceParamsWithAcsAndInvalidFreqRange(ifname),
                               getPskNwParams());
     EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
 }
@@ -272,8 +287,9 @@
     if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
     if (is_1_3(hostapd_))
         GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
+    std::string ifname = setupApIfaceIfNeededAndGetName();
     auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
-                              getIfaceParamsWithAcs(), getOpenNwParams());
+                              getIfaceParamsWithAcs(ifname), getOpenNwParams());
     EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
 }
 
@@ -284,8 +300,10 @@
 TEST_P(HostapdHidlTest, AddPskAccessPointWithoutAcs) {
     if (is_1_3(hostapd_))
         GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
-    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
-                              getIfaceParamsWithoutAcs(), getPskNwParams());
+    std::string ifname = setupApIfaceIfNeededAndGetName();
+    auto status =
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                    getIfaceParamsWithoutAcs(ifname), getPskNwParams());
     EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
 }
 
@@ -296,8 +314,10 @@
 TEST_P(HostapdHidlTest, AddOpenAccessPointWithoutAcs) {
     if (is_1_3(hostapd_))
         GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
-    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
-                              getIfaceParamsWithoutAcs(), getOpenNwParams());
+    std::string ifname = setupApIfaceIfNeededAndGetName();
+    auto status =
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                    getIfaceParamsWithoutAcs(ifname), getOpenNwParams());
     EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
 }
 
@@ -309,9 +329,10 @@
     if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
     if (is_1_3(hostapd_))
         GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
-    auto status =
-        HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
-                    getSaeTransitionNwParams());
+    std::string ifname = setupApIfaceIfNeededAndGetName();
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                              getIfaceParamsWithoutAcs(ifname),
+                              getSaeTransitionNwParams());
     EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
 }
 
@@ -323,8 +344,10 @@
     if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
     if (is_1_3(hostapd_))
         GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
-    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
-                              getIfaceParamsWithoutAcs(), getSaeNwParams());
+    std::string ifname = setupApIfaceIfNeededAndGetName();
+    auto status =
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                    getIfaceParamsWithoutAcs(ifname), getSaeNwParams());
     EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
 }
 
@@ -336,11 +359,12 @@
     if (!isAcsSupport_) GTEST_SKIP() << "Missing ACS support";
     if (is_1_3(hostapd_))
         GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
-    auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
-                                  getIfaceParamsWithAcs(), getPskNwParams());
+    std::string ifname = setupApIfaceIfNeededAndGetName();
+    auto status_1_2 =
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithAcs(ifname),
+                    getPskNwParams());
     EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
-    auto status =
-        HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
+    auto status = HIDL_INVOKE(hostapd_, removeAccessPoint, ifname);
     EXPECT_EQ(
         android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS,
         status.code);
@@ -353,11 +377,12 @@
 TEST_P(HostapdHidlTest, RemoveAccessPointWithoutAcs) {
     if (is_1_3(hostapd_))
         GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
-    auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
-                                  getIfaceParamsWithoutAcs(), getPskNwParams());
+    std::string ifname = setupApIfaceIfNeededAndGetName();
+    auto status_1_2 =
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                    getIfaceParamsWithoutAcs(ifname), getPskNwParams());
     EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
-    auto status =
-        HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
+    auto status = HIDL_INVOKE(hostapd_, removeAccessPoint, ifname);
     EXPECT_EQ(
         android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS,
         status.code);
@@ -370,9 +395,10 @@
 TEST_P(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) {
     if (is_1_3(hostapd_))
         GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
+    std::string ifname = setupApIfaceIfNeededAndGetName();
     auto status =
         HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
-                    getIfaceParamsWithInvalidChannel(), getPskNwParams());
+                    getIfaceParamsWithInvalidChannel(ifname), getPskNwParams());
     EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
 }
 
@@ -383,9 +409,10 @@
 TEST_P(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) {
     if (is_1_3(hostapd_))
         GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
+    std::string ifname = setupApIfaceIfNeededAndGetName();
     auto status =
-        HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
-                    getInvalidPskNwParams());
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                    getIfaceParamsWithoutAcs(ifname), getInvalidPskNwParams());
     EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
 }
 
@@ -397,9 +424,10 @@
     if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
     if (is_1_3(hostapd_))
         GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
-    auto status =
-        HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
-                    getInvalidSaeTransitionNwParams());
+    std::string ifname = setupApIfaceIfNeededAndGetName();
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                              getIfaceParamsWithoutAcs(ifname),
+                              getInvalidSaeTransitionNwParams());
     EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
 }
 
@@ -411,9 +439,10 @@
     if (!isWpa3SaeSupport_) GTEST_SKIP() << "Missing SAE support";
     if (is_1_3(hostapd_))
         GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
+    std::string ifname = setupApIfaceIfNeededAndGetName();
     auto status =
-        HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
-                    getInvalidSaeNwParams());
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                    getIfaceParamsWithoutAcs(ifname), getInvalidSaeNwParams());
     EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
 }
 
@@ -422,9 +451,9 @@
  * when hotspot interface doesn't init..
  */
 TEST_P(HostapdHidlTest, DisconnectClientWhenIfaceNotAvailable) {
-    auto status =
-        HIDL_INVOKE(hostapd_, forceClientDisconnect, getPrimaryWlanIfaceName(),
-                    kTestZeroMacAddr, kTestDisconnectReasonCode);
+    std::string ifname = setupApIfaceIfNeededAndGetName();
+    auto status = HIDL_INVOKE(hostapd_, forceClientDisconnect, ifname,
+                              kTestZeroMacAddr, kTestDisconnectReasonCode);
     EXPECT_EQ(HostapdStatusCode::FAILURE_IFACE_UNKNOWN, status.code);
 }
 
@@ -435,14 +464,14 @@
 TEST_P(HostapdHidlTest, DisconnectClientWhenIfacAvailable) {
     if (is_1_3(hostapd_))
         GTEST_SKIP() << "Ignore addAccessPoint_1_2 on hostapd 1_3";
+    std::string ifname = setupApIfaceIfNeededAndGetName();
     auto status_1_2 =
-        HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
-                    getOpenNwParams());
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                    getIfaceParamsWithoutAcs(ifname), getOpenNwParams());
     EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
 
-    status_1_2 =
-        HIDL_INVOKE(hostapd_, forceClientDisconnect, getPrimaryWlanIfaceName(),
-                    kTestZeroMacAddr, kTestDisconnectReasonCode);
+    status_1_2 = HIDL_INVOKE(hostapd_, forceClientDisconnect, ifname,
+                             kTestZeroMacAddr, kTestDisconnectReasonCode);
     EXPECT_EQ(HostapdStatusCode::FAILURE_CLIENT_UNKNOWN, status_1_2.code);
 }
 
diff --git a/wifi/hostapd/aidl/Android.bp b/wifi/hostapd/aidl/Android.bp
index c97f8da..54895c1 100644
--- a/wifi/hostapd/aidl/Android.bp
+++ b/wifi/hostapd/aidl/Android.bp
@@ -38,9 +38,7 @@
             min_sdk_version: "30",
         },
         ndk: {
-            vndk: {
-                enabled: true,
-            },
+            gen_trace: true,
         },
     },
     versions_with_info: [
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
index eabbf1b..da3ff3a 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test.cpp
@@ -38,11 +38,12 @@
     : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
    public:
     virtual void SetUp() override {
-        // Stop Wi-Fi
-        ASSERT_TRUE(stopWifiFramework());  // stop & wait for wifi to shutdown.
-
         wifi_instance_name_ = std::get<0>(GetParam());
         supplicant_instance_name_ = std::get<1>(GetParam());
+
+        // Stop & wait for wifi to shutdown.
+        ASSERT_TRUE(stopWifiFramework(wifi_instance_name_));
+
         std::system("/system/bin/start");
         ASSERT_TRUE(waitForFrameworkReady());
         isP2pOn_ =
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
index 086166a..6760663 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
@@ -28,26 +28,42 @@
 
 using ::android::sp;
 using ::android::hardware::configureRpcThreadpool;
-using ::android::hardware::joinRpcThreadpool;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
+using ::android::hardware::joinRpcThreadpool;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
-using ::android::hardware::wifi::V1_0::ChipModeId;
-using ::android::hardware::wifi::V1_0::IWifiChip;
+using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicant;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantIface;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantNetwork;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaIface;
 using ::android::hardware::wifi::supplicant::V1_0::ISupplicantStaNetwork;
-using ::android::hardware::wifi::supplicant::V1_0::ISupplicantP2pIface;
-using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::V1_0::ChipModeId;
+using ::android::hardware::wifi::V1_0::IWifi;
+using ::android::hardware::wifi::V1_0::IWifiChip;
 using ::android::wifi_system::InterfaceTool;
 using ::android::wifi_system::SupplicantManager;
 
 namespace {
+
+bool waitForWifiHalStop(const std::string& wifi_instance_name) {
+    sp<IWifi> wifi = getWifi(wifi_instance_name);
+    int count = 50; /* wait at most 5 seconds for completion */
+    while (count-- > 0) {
+        if (wifi != nullptr && !wifi->isStarted()) {
+            return true;
+        }
+        usleep(100000);
+        wifi = getWifi(wifi_instance_name);
+    }
+    LOG(ERROR) << "Wifi HAL was not stopped";
+    return false;
+}
+
 bool waitForSupplicantState(bool is_running) {
     SupplicantManager supplicant_manager;
     int count = 50; /* wait at most 5 seconds for completion */
@@ -113,10 +129,10 @@
     return waitForSupplicantStart();  // wait for wifi to start.
 }
 
-bool stopWifiFramework() {
+bool stopWifiFramework(const std::string& wifi_instance_name) {
     std::system("svc wifi disable");
     std::system("cmd wifi set-scan-always-available disabled");
-    return waitForSupplicantStop();  // wait for wifi to shutdown.
+    return waitForSupplicantStop() && waitForWifiHalStop(wifi_instance_name);
 }
 
 void stopSupplicant() { stopSupplicant(""); }
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
index 7228623..2198d7c 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.h
@@ -33,7 +33,7 @@
 bool startWifiFramework();
 
 // Used to stop the android wifi framework before every test.
-bool stopWifiFramework();
+bool stopWifiFramework(const std::string& wifi_instance_name);
 
 void stopSupplicant(const std::string& wifi_instance_name);
 // Used to configure the chip, driver and start wpa_supplicant before every
@@ -77,12 +77,13 @@
     : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
    public:
     virtual void SetUp() override {
-        // Stop Wi-Fi
-        ASSERT_TRUE(stopWifiFramework());  // stop & wait for wifi to shutdown.
-
-        // should always be v1.0 wifi
-        wifi_v1_0_instance_name_ = std::get<0>(GetParam());
+        wifi_v1_0_instance_name_ =
+            std::get<0>(GetParam());  // should always be v1.0 wifi
         supplicant_instance_name_ = std::get<1>(GetParam());
+
+        // Stop & wait for wifi to shutdown.
+        ASSERT_TRUE(stopWifiFramework(wifi_v1_0_instance_name_));
+
         std::system("/system/bin/start");
         ASSERT_TRUE(waitForFrameworkReady());
         isP2pOn_ =
diff --git a/wifi/supplicant/aidl/Android.bp b/wifi/supplicant/aidl/Android.bp
index ca0785b..9cb4e51 100644
--- a/wifi/supplicant/aidl/Android.bp
+++ b/wifi/supplicant/aidl/Android.bp
@@ -38,9 +38,7 @@
             min_sdk_version: "30",
         },
         ndk: {
-            vndk: {
-                enabled: true,
-            },
+            gen_trace: true,
         },
     },
     versions_with_info: [
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h b/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
index 17e0394..31042a2 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
@@ -78,7 +78,7 @@
 void stopSupplicantService() { stopSupplicant(getWifiInstanceName()); }
 
 void initializeService() {
-    ASSERT_TRUE(stopWifiFramework());
+    ASSERT_TRUE(stopWifiFramework(getWifiInstanceName()));
     std::system("/system/bin/start");
     ASSERT_TRUE(waitForFrameworkReady());
     stopSupplicantService();