Merge "RKP HAL: fix typos"
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index d4c1e85..d6e6f50 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -148,6 +148,7 @@
     vendor_available: true,
     srcs: [
         "android/hardware/audio/effect/Descriptor.aidl",
+        "android/hardware/audio/effect/IEffect.aidl",
         "android/hardware/audio/effect/IFactory.aidl",
     ],
     imports: [
@@ -165,3 +166,19 @@
         },
     },
 }
+
+latest_android_hardware_audio_effect = "android.hardware.audio.effect-V1"
+
+cc_defaults {
+    name: "latest_android_hardware_audio_effect_ndk_shared",
+    shared_libs: [
+        latest_android_hardware_audio_effect + "-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "latest_android_hardware_audio_effect_ndk_static",
+    static_libs: [
+        latest_android_hardware_audio_effect + "-ndk",
+    ],
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IEffect.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IEffect.aidl
new file mode 100644
index 0000000..7f868ad
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IEffect.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.effect;
+@VintfStability
+interface IEffect {
+  void open();
+  void close();
+  android.hardware.audio.effect.Descriptor getDescriptor();
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl
index b6c9aab..db06475 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl
@@ -35,4 +35,6 @@
 @VintfStability
 interface IFactory {
   android.hardware.audio.effect.Descriptor.Identity[] queryEffects(in @nullable android.media.audio.common.AudioUuid type, in @nullable android.media.audio.common.AudioUuid implementation);
+  android.hardware.audio.effect.IEffect createEffect(in android.media.audio.common.AudioUuid implUuid);
+  void destroyEffect(in android.hardware.audio.effect.IEffect handle);
 }
diff --git a/audio/aidl/android/hardware/audio/effect/IEffect.aidl b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
new file mode 100644
index 0000000..d7a9501
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
@@ -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.
+ */
+
+package android.hardware.audio.effect;
+
+import android.hardware.audio.effect.Descriptor;
+
+/**
+ * Effect interfaces definitions to configure and control the effect instance.
+ */
+@VintfStability
+interface IEffect {
+    /**
+     * Open an effect instance, effect should not start processing data before receive START
+     * command. All necessary information should be allocated and instance should transfer to IDLE
+     * state after open() call has been handled successfully.
+     * After open, the effect instance should be able to handle all IEffect interface calls.
+     *
+     * @throws a EX_UNSUPPORTED_OPERATION if device capability/resource is not enough or system
+     *         failure happens.
+     * @note Open an already-opened effect instance should do nothing and should not throw an error.
+     */
+    void open();
+
+    /**
+     * Called by the client to close the effect instance, processing thread should be destroyed and
+     * consume no CPU after close.
+     *
+     * It is recommended to close the effect on the client side as soon as it becomes unused, it's
+     * client responsibility to make sure all parameter/buffer is correct if client wants to reopen
+     * a closed instance.
+     *
+     * Effect instance close interface should always succeed unless:
+     * 1. The effect instance is not in a proper state to be closed, for example it's still in
+     * processing state.
+     * 2. There is system/hardware related failure when close.
+     *
+     * @throws EX_ILLEGAL_STATE if the effect instance is not in a proper state to be closed.
+     * @throws EX_UNSUPPORTED_OPERATION if the effect instance failed to close for any other reason.
+     * @note Close an already-closed effect should do nothing and should not throw an error.
+     */
+    void close();
+
+    /**
+     * Return the @c Descriptor of this effect instance.
+     *
+     * Must be available for the effect instance at anytime and should always succeed.
+     *
+     * @return Descriptor The @c Descriptor of this effect instance.
+     */
+    Descriptor getDescriptor();
+}
diff --git a/audio/aidl/android/hardware/audio/effect/IFactory.aidl b/audio/aidl/android/hardware/audio/effect/IFactory.aidl
index 99c2e6a..4873d3a 100644
--- a/audio/aidl/android/hardware/audio/effect/IFactory.aidl
+++ b/audio/aidl/android/hardware/audio/effect/IFactory.aidl
@@ -17,6 +17,7 @@
 package android.hardware.audio.effect;
 
 import android.hardware.audio.effect.Descriptor;
+import android.hardware.audio.effect.IEffect;
 import android.media.audio.common.AudioUuid;
 
 /**
@@ -42,4 +43,30 @@
      */
     Descriptor.Identity[] queryEffects(
             in @nullable AudioUuid type, in @nullable AudioUuid implementation);
+
+    /**
+     * Called by the audio framework to create the effect (identified by the implementation UUID
+     * parameter).
+     *
+     * The effect instance should be able to maintain its own context and parameters after creation.
+     *
+     * @param implUuid UUID for the effect implementation which instance will be created based on.
+     * @return The effect instance handle created.
+     * @throws EX_ILLEGAL_ARGUMENT if the implUuid is not valid.
+     * @throws EX_TRANSACTION_FAILED if device capability/resource is not enough to create the
+     *         effect instance.
+     */
+    IEffect createEffect(in AudioUuid implUuid);
+
+    /**
+     * Called by the framework to destroy the effect and free up all currently allocated resources.
+     * It is recommended to destroy the effect from the client side as soon as it is becomes unused.
+     *
+     * The client must ensure effect instance is closed before destroy.
+     *
+     * @param handle The handle of effect instance to be destroyed.
+     * @throws EX_ILLEGAL_ARGUMENT if the effect handle is not valid.
+     * @throws EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
+     */
+    void destroyEffect(in IEffect handle);
 }
diff --git a/audio/aidl/common/include/Utils.h b/audio/aidl/common/include/Utils.h
index 74549d4..1026134 100644
--- a/audio/aidl/common/include/Utils.h
+++ b/audio/aidl/common/include/Utils.h
@@ -16,8 +16,13 @@
 
 #pragma once
 
+#include <initializer_list>
+#include <type_traits>
+
 #include <aidl/android/media/audio/common/AudioChannelLayout.h>
 #include <aidl/android/media/audio/common/AudioFormatDescription.h>
+#include <aidl/android/media/audio/common/AudioInputFlags.h>
+#include <aidl/android/media/audio/common/AudioOutputFlags.h>
 #include <aidl/android/media/audio/common/PcmType.h>
 
 namespace android::hardware::audio::common {
@@ -78,4 +83,34 @@
     return 0;
 }
 
+// The helper functions defined below are only applicable to the case when an enum type
+// specifies zero-based bit positions, not bit masks themselves. This is why instantiation
+// is restricted to certain enum types.
+template <typename E>
+using is_bit_position_enum = std::integral_constant<
+        bool, std::is_same_v<E, ::aidl::android::media::audio::common::AudioInputFlags> ||
+                      std::is_same_v<E, ::aidl::android::media::audio::common::AudioOutputFlags>>;
+
+template <typename E, typename U = std::underlying_type_t<E>,
+          typename = std::enable_if_t<is_bit_position_enum<E>::value>>
+constexpr U makeBitPositionFlagMask(E flag) {
+    return 1 << static_cast<U>(flag);
+}
+
+template <typename E, typename U = std::underlying_type_t<E>,
+          typename = std::enable_if_t<is_bit_position_enum<E>::value>>
+constexpr bool isBitPositionFlagSet(U mask, E flag) {
+    return (mask & makeBitPositionFlagMask(flag)) != 0;
+}
+
+template <typename E, typename U = std::underlying_type_t<E>,
+          typename = std::enable_if_t<is_bit_position_enum<E>::value>>
+constexpr U makeBitPositionFlagMask(std::initializer_list<E> flags) {
+    U result = 0;
+    for (const auto flag : flags) {
+        result |= makeBitPositionFlagMask(flag);
+    }
+    return result;
+}
+
 }  // namespace android::hardware::audio::common
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 5d63347..53ed908 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -68,6 +68,7 @@
         "libbase",
         "libbinder_ndk",
         "android.hardware.audio.effect-V1-ndk",
+        "libequalizer",
     ],
     cflags: [
         "-Wall",
@@ -80,7 +81,10 @@
 cc_library_static {
     name: "libaudioeffectserviceexampleimpl",
     defaults: ["aidlaudioeffectservice_defaults"],
-    export_include_dirs: ["include"],
+    export_include_dirs: [
+        "include",
+        "include/equalizer-impl/",
+    ],
     srcs: [
         "EffectFactory.cpp",
     ],
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index f5d679b..a3e5ff7 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <Utils.h>
 #include <aidl/android/media/audio/common/AudioChannelLayout.h>
 #include <aidl/android/media/audio/common/AudioDeviceType.h>
 #include <aidl/android/media/audio/common/AudioFormatDescription.h>
@@ -40,6 +41,7 @@
 using aidl::android::media::audio::common::AudioProfile;
 using aidl::android::media::audio::common::Int;
 using aidl::android::media::audio::common::PcmType;
+using android::hardware::audio::common::makeBitPositionFlagMask;
 
 namespace aidl::android::hardware::audio::core::internal {
 
@@ -193,7 +195,7 @@
                                  createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0)));
 
         AudioPort primaryOutMix = createPort(c.nextPortId++, "primary output",
-                                             1 << static_cast<int32_t>(AudioOutputFlags::PRIMARY),
+                                             makeBitPositionFlagMask(AudioOutputFlags::PRIMARY),
                                              false, createPortMixExt(1, 1));
         primaryOutMix.profiles.insert(primaryOutMix.profiles.begin(),
                                       standardPcmAudioProfiles.begin(),
@@ -202,9 +204,9 @@
 
         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),
+                           makeBitPositionFlagMask({AudioOutputFlags::DIRECT,
+                                                    AudioOutputFlags::COMPRESS_OFFLOAD,
+                                                    AudioOutputFlags::NON_BLOCKING}),
                            false, createPortMixExt(1, 1));
         compressedOffloadOutMix.profiles.push_back(
                 createProfile(::android::MEDIA_MIMETYPE_AUDIO_MPEG,
diff --git a/audio/aidl/default/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp
index a31e23f..a9848fd 100644
--- a/audio/aidl/default/EffectFactory.cpp
+++ b/audio/aidl/default/EffectFactory.cpp
@@ -29,19 +29,8 @@
     // TODO: implement this with xml parser on audio_effect.xml, and filter with optional
     // parameters.
     Descriptor::Identity id;
-    id.type = {static_cast<int32_t>(0x0bed4300),
-               0xddd6,
-               0x11db,
-               0x8f34,
-               {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
-    id.uuid = EqualizerUUID;
-    mIdentityList.push_back(id);
-    id.type = {static_cast<int32_t>(0xd3467faa),
-               0xacc7,
-               0x4d34,
-               0xacaf,
-               {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
-    id.uuid = VisualizerUUID;
+    id.type = EqualizerTypeUUID;
+    id.uuid = EqualizerSwImplUUID;
     mIdentityList.push_back(id);
 }
 
@@ -56,4 +45,28 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Factory::createEffect(
+        const AudioUuid& in_impl_uuid,
+        std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>* _aidl_return) {
+    LOG(DEBUG) << __func__ << ": UUID " << in_impl_uuid.toString();
+    if (in_impl_uuid == EqualizerSwImplUUID) {
+        *_aidl_return = ndk::SharedRefBase::make<Equalizer>();
+    } else {
+        LOG(ERROR) << __func__ << ": UUID "
+                   << " not supported";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Factory::destroyEffect(
+        const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_handle) {
+    if (in_handle) {
+        // TODO: b/245393900 need check the instance state with IEffect.getState before destroy.
+        return ndk::ScopedAStatus::ok();
+    } else {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+}
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectMain.cpp b/audio/aidl/default/EffectMain.cpp
index 3b3c39b..3219dd6 100644
--- a/audio/aidl/default/EffectMain.cpp
+++ b/audio/aidl/default/EffectMain.cpp
@@ -23,10 +23,11 @@
 int main() {
     // This is a debug implementation, always enable debug logging.
     android::base::SetMinimumLogSeverity(::android::base::DEBUG);
-    ABinderProcess_setThreadPoolMaxThreadCount(16);
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
 
     auto effectFactory =
             ndk::SharedRefBase::make<aidl::android::hardware::audio::effect::Factory>();
+
     std::string serviceName = std::string() + effectFactory->descriptor + "/default";
     binder_status_t status =
             AServiceManager_addService(effectFactory->asBinder().get(), serviceName.c_str());
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index af033d0..deaca49 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -43,6 +43,7 @@
 using aidl::android::media::audio::common::Int;
 using aidl::android::media::audio::common::PcmType;
 using android::hardware::audio::common::getFrameSizeInBytes;
+using android::hardware::audio::common::isBitPositionFlagSet;
 
 namespace aidl::android::hardware::audio::core {
 
@@ -125,11 +126,11 @@
     }
     const auto& flags = portConfigIt->flags.value();
     if ((flags.getTag() == AudioIoFlags::Tag::input &&
-         (flags.get<AudioIoFlags::Tag::input>() &
-          1 << static_cast<int32_t>(AudioInputFlags::MMAP_NOIRQ)) == 0) ||
+         !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::input>(),
+                               AudioInputFlags::MMAP_NOIRQ)) ||
         (flags.getTag() == AudioIoFlags::Tag::output &&
-         (flags.get<AudioIoFlags::Tag::output>() &
-          1 << static_cast<int32_t>(AudioOutputFlags::MMAP_NOIRQ)) == 0)) {
+         !isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::output>(),
+                               AudioOutputFlags::MMAP_NOIRQ))) {
         StreamContext temp(
                 std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
                 std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
@@ -478,9 +479,9 @@
                    << " does not correspond to an output mix port";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
-    if ((port->flags.get<AudioIoFlags::Tag::output>() &
-         1 << static_cast<int32_t>(AudioOutputFlags::COMPRESS_OFFLOAD)) != 0 &&
-        !in_args.offloadInfo.has_value()) {
+    const bool isOffload = isBitPositionFlagSet(port->flags.get<AudioIoFlags::Tag::output>(),
+                                                AudioOutputFlags::COMPRESS_OFFLOAD);
+    if (isOffload && !in_args.offloadInfo.has_value()) {
         LOG(ERROR) << __func__ << ": port id " << port->id
                    << " has COMPRESS_OFFLOAD flag set, requires offload info";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
diff --git a/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc b/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc
index 01c0e6e..68bbf5b 100644
--- a/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc
+++ b/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc
@@ -2,7 +2,7 @@
     class hal
     user audioserver
     # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
-    group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock context_hub
+    group audio media
     capabilities BLOCK_SUSPEND
     ioprio rt 4
     task_profiles ProcessCapacityHigh HighPerformance
diff --git a/audio/aidl/default/equalizer/Android.bp b/audio/aidl/default/equalizer/Android.bp
new file mode 100644
index 0000000..b842149
--- /dev/null
+++ b/audio/aidl/default/equalizer/Android.bp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+    name: "libequalizer",
+    vendor: true,
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libstagefright_foundation",
+    ],
+    defaults: [
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    include_dirs: ["hardware/interfaces/audio/aidl/default/include/equalizer-impl"],
+    srcs: [
+        "Equalizer.cpp",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/equalizer/Equalizer.cpp b/audio/aidl/default/equalizer/Equalizer.cpp
new file mode 100644
index 0000000..8b157fa
--- /dev/null
+++ b/audio/aidl/default/equalizer/Equalizer.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_Equalizer"
+#include <android-base/logging.h>
+
+#include "Equalizer.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+ndk::ScopedAStatus Equalizer::open() {
+    LOG(DEBUG) << __func__;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Equalizer::close() {
+    LOG(DEBUG) << __func__;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Equalizer::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << "descriptor " << mDesc.toString();
+    *_aidl_return = mDesc;
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 816cdb1..488edf1 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -229,10 +229,9 @@
     }
     void setStreamIsConnected(bool connected) {
         std::visit(
-                [&](auto&& ws) -> bool {
+                [&](auto&& ws) {
                     auto s = ws.lock();
                     if (s) s->setIsConnected(connected);
-                    return !!s;
                 },
                 mStream);
     }
@@ -253,7 +252,7 @@
     }
     void insert(int32_t portId, int32_t portConfigId, StreamWrapper sw) {
         mStreams.insert(std::pair{portConfigId, sw});
-        mStreams.insert(std::pair{portId, sw});
+        mStreams.insert(std::pair{portId, std::move(sw)});
     }
     void setStreamIsConnected(int32_t portConfigId, bool connected) {
         if (auto it = mStreams.find(portConfigId); it != mStreams.end()) {
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
index 7670250..8da5525 100644
--- a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
+++ b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
@@ -40,6 +40,28 @@
             const std::optional<::aidl::android::media::audio::common::AudioUuid>& in_instance,
             std::vector<Descriptor::Identity>* out_descriptor) override;
 
+    /**
+     * @brief Create an effect instance for a certain implementation (identified by UUID).
+     *
+     * @param in_impl_uuid Effect implementation UUID.
+     * @param _aidl_return A pointer to created effect instance.
+     * @return ndk::ScopedAStatus
+     */
+    ndk::ScopedAStatus createEffect(
+            const ::aidl::android::media::audio::common::AudioUuid& in_impl_uuid,
+            std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>* _aidl_return)
+            override;
+
+    /**
+     * @brief Destroy an effect instance.
+     *
+     * @param in_handle Effect instance handle.
+     * @return ndk::ScopedAStatus
+     */
+    ndk::ScopedAStatus destroyEffect(
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_handle)
+            override;
+
   private:
     // List of effect descriptors supported by the devices.
     std::vector<Descriptor::Identity> mIdentityList;
diff --git a/audio/aidl/default/include/equalizer-impl/Equalizer.h b/audio/aidl/default/include/equalizer-impl/Equalizer.h
index 86f8c3a..ea16cb9 100644
--- a/audio/aidl/default/include/equalizer-impl/Equalizer.h
+++ b/audio/aidl/default/include/equalizer-impl/Equalizer.h
@@ -16,16 +16,36 @@
 
 #pragma once
 
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
 #include <cstdlib>
 
 namespace aidl::android::hardware::audio::effect {
 
+// Equalizer type UUID.
+static const ::aidl::android::media::audio::common::AudioUuid EqualizerTypeUUID = {
+        static_cast<int32_t>(0x0bed4300),
+        0xddd6,
+        0x11db,
+        0x8f34,
+        {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+
 // Equalizer implementation UUID.
-static const ::aidl::android::media::audio::common::AudioUuid EqualizerUUID = {
-        static_cast<int32_t>(0xce772f20),
+static const ::aidl::android::media::audio::common::AudioUuid EqualizerSwImplUUID = {
+        static_cast<int32_t>(0x0bed4300),
         0x847d,
         0x11df,
         0xbb17,
         {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
 
-}  // namespace aidl::android::hardware::audio::effect
\ No newline at end of file
+class Equalizer : public BnEffect {
+  public:
+    Equalizer() = default;
+    ndk::ScopedAStatus open() override;
+    ndk::ScopedAStatus close() override;
+    ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+
+  private:
+    // Effect descriptor.
+    Descriptor mDesc = {.common = {.id = {.type = EqualizerTypeUUID, .uuid = EqualizerSwImplUUID}}};
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp
index e36ab4a..33c5b72 100644
--- a/audio/aidl/vts/ModuleConfig.cpp
+++ b/audio/aidl/vts/ModuleConfig.cpp
@@ -17,6 +17,7 @@
 #include <algorithm>
 #include <chrono>
 
+#include <Utils.h>
 #include <aidl/android/media/audio/common/AudioIoFlags.h>
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
 
@@ -39,14 +40,15 @@
 using aidl::android::media::audio::common::AudioProfile;
 using aidl::android::media::audio::common::AudioUsage;
 using aidl::android::media::audio::common::Int;
+using android::hardware::audio::common::isBitPositionFlagSet;
 
 // 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) {
+        isBitPositionFlagSet(portConfig.flags.value().get<AudioIoFlags::Tag::output>(),
+                             AudioOutputFlags::COMPRESS_OFFLOAD)) {
         AudioOffloadInfo offloadInfo;
         offloadInfo.base.sampleRate = portConfig.sampleRate.value().value;
         offloadInfo.base.channelMask = portConfig.channelMask.value();
@@ -123,6 +125,23 @@
     return result;
 }
 
+std::vector<AudioPort> ModuleConfig::getOffloadMixPorts(bool attachedOnly, bool singlePort) const {
+    std::vector<AudioPort> result;
+    const auto mixPorts = getMixPorts(false /*isInput*/);
+    auto offloadPortIt = mixPorts.begin();
+    while (offloadPortIt != mixPorts.end()) {
+        offloadPortIt = std::find_if(offloadPortIt, mixPorts.end(), [&](const AudioPort& port) {
+            return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+                                        AudioOutputFlags::COMPRESS_OFFLOAD) &&
+                   (!attachedOnly || !getAttachedSinkDevicesPortsForMixPort(port).empty());
+        });
+        if (offloadPortIt == mixPorts.end()) break;
+        result.push_back(*offloadPortIt++);
+        if (singlePort) break;
+    }
+    return result;
+}
+
 std::vector<AudioPort> ModuleConfig::getAttachedDevicesPortsForMixPort(
         bool isInput, const AudioPortConfig& mixPortConfig) const {
     const auto mixPortIt = findById<AudioPort>(mPorts, mixPortConfig.portId);
diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h
index 552f971..dc109a7 100644
--- a/audio/aidl/vts/ModuleConfig.h
+++ b/audio/aidl/vts/ModuleConfig.h
@@ -48,6 +48,8 @@
     std::vector<aidl::android::media::audio::common::AudioPort> getMixPorts(bool isInput) const {
         return isInput ? getInputMixPorts() : getOutputMixPorts();
     }
+    std::vector<aidl::android::media::audio::common::AudioPort> getOffloadMixPorts(
+            bool attachedOnly, bool singlePort) const;
 
     std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicesPortsForMixPort(
             bool isInput, const aidl::android::media::audio::common::AudioPort& mixPort) const {
diff --git a/audio/aidl/vts/TestUtils.h b/audio/aidl/vts/TestUtils.h
new file mode 100644
index 0000000..2fc109a
--- /dev/null
+++ b/audio/aidl/vts/TestUtils.h
@@ -0,0 +1,73 @@
+/*
+ * 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 <iostream>
+
+#include <android/binder_auto_utils.h>
+#include <gtest/gtest_pred_impl.h>
+
+namespace ndk {
+
+std::ostream& operator<<(std::ostream& str, const ScopedAStatus& status) {
+    str << status.getDescription();
+    return str;
+}
+
+}  // namespace ndk
+
+namespace android::hardware::audio::common::testing {
+
+namespace detail {
+
+inline ::testing::AssertionResult assertIsOk(const char* expr, const ::ndk::ScopedAStatus& status) {
+    if (status.isOk()) {
+        return ::testing::AssertionSuccess();
+    }
+    return ::testing::AssertionFailure()
+           << "Expected the transaction \'" << expr << "\' to succeed\n"
+           << "  but it has failed with: " << status;
+}
+
+inline ::testing::AssertionResult assertResult(const char* exp_expr, const char* act_expr,
+                                               int32_t expected,
+                                               const ::ndk::ScopedAStatus& status) {
+    if (status.getExceptionCode() == expected) {
+        return ::testing::AssertionSuccess();
+    }
+    return ::testing::AssertionFailure()
+           << "Expected the transaction \'" << act_expr << "\' to fail with " << exp_expr
+           << "\n  but is has completed with: " << status;
+}
+
+}  // namespace detail
+
+}  // namespace android::hardware::audio::common::testing
+
+// Test that the transaction status 'isOk'
+#define ASSERT_IS_OK(ret) \
+    ASSERT_PRED_FORMAT1(::android::hardware::audio::common::testing::detail::assertIsOk, ret)
+#define EXPECT_IS_OK(ret) \
+    EXPECT_PRED_FORMAT1(::android::hardware::audio::common::testing::detail::assertIsOk, ret)
+
+// Test that the transaction status is as expected.
+#define ASSERT_STATUS(expected, ret)                                                       \
+    ASSERT_PRED_FORMAT2(::android::hardware::audio::common::testing::detail::assertResult, \
+                        expected, ret)
+#define EXPECT_STATUS(expected, ret)                                                       \
+    EXPECT_PRED_FORMAT2(::android::hardware::audio::common::testing::detail::assertResult, \
+                        expected, ret)
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
index ab70ec4..2381200 100644
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
@@ -26,6 +26,7 @@
 #include <android-base/logging.h>
 
 #include <StreamWorker.h>
+#include <Utils.h>
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
 #include <aidl/android/hardware/audio/core/IConfig.h>
@@ -37,6 +38,7 @@
 
 #include "AudioHalBinderServiceUtil.h"
 #include "ModuleConfig.h"
+#include "TestUtils.h"
 
 using namespace android;
 using aidl::android::hardware::audio::common::PlaybackTrackMetadata;
@@ -64,17 +66,11 @@
 using aidl::android::media::audio::common::AudioPortExt;
 using aidl::android::media::audio::common::AudioSource;
 using aidl::android::media::audio::common::AudioUsage;
+using android::hardware::audio::common::isBitPositionFlagSet;
 using android::hardware::audio::common::StreamLogic;
 using android::hardware::audio::common::StreamWorker;
 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) {
     return std::find_if(v.begin(), v.end(), [&](const auto& e) { return e.id == id; });
@@ -97,20 +93,6 @@
     return AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(std::to_string(++nextId));
 }
 
-template <typename T>
-struct IsInput {
-    constexpr operator bool() const;
-};
-
-template <>
-constexpr IsInput<IStreamIn>::operator bool() const {
-    return true;
-}
-template <>
-constexpr IsInput<IStreamOut>::operator bool() const {
-    return false;
-}
-
 // All 'With*' classes are move-only because they are associated with some
 // resource or state of a HAL module.
 class WithDebugFlags {
@@ -125,14 +107,10 @@
     WithDebugFlags& operator=(const WithDebugFlags&) = delete;
     ~WithDebugFlags() {
         if (mModule != nullptr) {
-            ScopedAStatus status = mModule->setModuleDebug(mInitial);
-            EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status;
+            EXPECT_IS_OK(mModule->setModuleDebug(mInitial));
         }
     }
-    void SetUp(IModule* module) {
-        ScopedAStatus status = module->setModuleDebug(mFlags);
-        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
-    }
+    void SetUp(IModule* module) { ASSERT_IS_OK(module->setModuleDebug(mFlags)); }
     ModuleDebug& flags() { return mFlags; }
 
   private:
@@ -153,9 +131,7 @@
     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();
+            EXPECT_IS_OK(mModule->resetAudioPortConfig(getId())) << "port config id " << getId();
         }
     }
     void SetUp(IModule* module) {
@@ -174,9 +150,8 @@
         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();
+            ASSERT_IS_OK(module->setAudioPortConfig(mInitialConfig, &suggested, &applied))
+                    << "Config: " << mInitialConfig.toString();
             if (!applied && negotiate) {
                 mInitialConfig = suggested;
                 ASSERT_NO_FATAL_FAILURE(SetUpImpl(module, false))
@@ -209,9 +184,7 @@
 
     void TearDown() override {
         if (module != nullptr) {
-            ScopedAStatus status = module->setModuleDebug(ModuleDebug{});
-            EXPECT_EQ(EX_NONE, status.getExceptionCode())
-                    << status << " returned when resetting debug flags";
+            EXPECT_IS_OK(module->setModuleDebug(ModuleDebug{}));
         }
     }
 
@@ -234,8 +207,7 @@
             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;
+            ASSERT_IS_OK(module->getAudioPortConfigs(&retrievedPortConfigs));
             const int32_t portConfigId = portConfig.getId();
             auto configIt = std::find_if(
                     retrievedPortConfigs.begin(), retrievedPortConfigs.end(),
@@ -258,10 +230,7 @@
                          ScopedAStatus (IModule::*getter)(std::vector<Entity>*),
                          const std::string& errorMessage) {
         std::vector<Entity> entities;
-        {
-            ScopedAStatus status = (module.get()->*getter)(&entities);
-            ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
-        }
+        { ASSERT_IS_OK((module.get()->*getter)(&entities)); }
         std::transform(entities.begin(), entities.end(),
                        std::inserter(*entityIds, entityIds->begin()),
                        [](const auto& entity) { return entity.id; });
@@ -309,16 +278,13 @@
     WithDevicePortConnectedState& operator=(const WithDevicePortConnectedState&) = delete;
     ~WithDevicePortConnectedState() {
         if (mModule != nullptr) {
-            ScopedAStatus status = mModule->disconnectExternalDevice(getId());
-            EXPECT_EQ(EX_NONE, status.getExceptionCode())
-                    << status << " returned when disconnecting device port ID " << getId();
+            EXPECT_IS_OK(mModule->disconnectExternalDevice(getId()))
+                    << "when disconnecting device port ID " << getId();
         }
     }
     void SetUp(IModule* module) {
-        ScopedAStatus status = module->connectExternalDevice(mIdAndData, &mConnectedPort);
-        ASSERT_EQ(EX_NONE, status.getExceptionCode())
-                << status << " returned when connecting device port ID & data "
-                << mIdAndData.toString();
+        ASSERT_IS_OK(module->connectExternalDevice(mIdAndData, &mConnectedPort))
+                << "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;
@@ -556,9 +522,7 @@
     ~WithStream() {
         if (mStream != nullptr) {
             mContext.reset();
-            ScopedAStatus status = mStream->close();
-            EXPECT_EQ(EX_NONE, status.getExceptionCode())
-                    << status << "; port config id " << getPortId();
+            EXPECT_IS_OK(mStream->close()) << "port config id " << getPortId();
         }
     }
     void SetUpPortConfig(IModule* module) { ASSERT_NO_FATAL_FAILURE(mPortConfig.SetUp(module)); }
@@ -569,10 +533,8 @@
                                 long bufferSizeFrames);
     void SetUp(IModule* module, long bufferSizeFrames) {
         ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module));
-        ScopedAStatus status = SetUpNoChecks(module, bufferSizeFrames);
-        ASSERT_EQ(EX_NONE, status.getExceptionCode())
-                << status << "; port config id " << getPortId();
-        ASSERT_NE(nullptr, mStream) << "; port config id " << getPortId();
+        ASSERT_IS_OK(SetUpNoChecks(module, bufferSizeFrames)) << "port config id " << getPortId();
+        ASSERT_NE(nullptr, mStream) << "port config id " << getPortId();
         EXPECT_GE(mDescriptor.bufferSizeFrames, bufferSizeFrames)
                 << "actual buffer size must be no less than requested";
         mContext.emplace(mDescriptor);
@@ -660,8 +622,7 @@
     WithAudioPatch& operator=(const WithAudioPatch&) = delete;
     ~WithAudioPatch() {
         if (mModule != nullptr && mPatch.id != 0) {
-            ScopedAStatus status = mModule->resetAudioPatch(mPatch.id);
-            EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status << "; patch id " << getId();
+            EXPECT_IS_OK(mModule->resetAudioPatch(mPatch.id)) << "patch id " << getId();
         }
     }
     void SetUpPortConfigs(IModule* module) {
@@ -676,10 +637,8 @@
     }
     void SetUp(IModule* module) {
         ASSERT_NO_FATAL_FAILURE(SetUpPortConfigs(module));
-        ScopedAStatus status = SetUpNoChecks(module);
-        ASSERT_EQ(EX_NONE, status.getExceptionCode())
-                << status << "; source port config id " << mSrcPortConfig.getId()
-                << "; sink port config id " << mSinkPortConfig.getId();
+        ASSERT_IS_OK(SetUpNoChecks(module)) << "source port config id " << mSrcPortConfig.getId()
+                                            << "; sink port config id " << mSinkPortConfig.getId();
         EXPECT_GT(mPatch.minimumStreamBufferSizeFrames, 0) << "patch id " << getId();
         for (auto latencyMs : mPatch.latenciesMs) {
             EXPECT_GT(latencyMs, 0) << "patch id " << getId();
@@ -715,15 +674,9 @@
 
 TEST_P(AudioCoreModule, GetAudioPortsIsStable) {
     std::vector<AudioPort> ports1;
-    {
-        ScopedAStatus status = module->getAudioPorts(&ports1);
-        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
-    }
+    ASSERT_IS_OK(module->getAudioPorts(&ports1));
     std::vector<AudioPort> ports2;
-    {
-        ScopedAStatus status = module->getAudioPorts(&ports2);
-        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
-    }
+    ASSERT_IS_OK(module->getAudioPorts(&ports2));
     ASSERT_EQ(ports1.size(), ports2.size())
             << "Sizes of audio port arrays do not match across consequent calls to getAudioPorts";
     std::sort(ports1.begin(), ports1.end());
@@ -733,15 +686,9 @@
 
 TEST_P(AudioCoreModule, GetAudioRoutesIsStable) {
     std::vector<AudioRoute> routes1;
-    {
-        ScopedAStatus status = module->getAudioRoutes(&routes1);
-        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
-    }
+    ASSERT_IS_OK(module->getAudioRoutes(&routes1));
     std::vector<AudioRoute> routes2;
-    {
-        ScopedAStatus status = module->getAudioRoutes(&routes2);
-        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
-    }
+    ASSERT_IS_OK(module->getAudioRoutes(&routes2));
     ASSERT_EQ(routes1.size(), routes2.size())
             << "Sizes of audio route arrays do not match across consequent calls to getAudioRoutes";
     std::sort(routes1.begin(), routes1.end());
@@ -751,10 +698,7 @@
 
 TEST_P(AudioCoreModule, GetAudioRoutesAreValid) {
     std::vector<AudioRoute> routes;
-    {
-        ScopedAStatus status = module->getAudioRoutes(&routes);
-        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
-    }
+    ASSERT_IS_OK(module->getAudioRoutes(&routes));
     for (const auto& route : routes) {
         std::set<int32_t> sources(route.sourcePortIds.begin(), route.sourcePortIds.end());
         EXPECT_NE(0UL, sources.size())
@@ -769,10 +713,7 @@
     std::set<int32_t> portIds;
     ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
     std::vector<AudioRoute> routes;
-    {
-        ScopedAStatus status = module->getAudioRoutes(&routes);
-        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
-    }
+    ASSERT_IS_OK(module->getAudioRoutes(&routes));
     for (const auto& route : routes) {
         EXPECT_EQ(1UL, portIds.count(route.sinkPortId))
                 << route.sinkPortId << " sink port id is unknown";
@@ -790,8 +731,7 @@
     }
     for (const auto portId : portIds) {
         std::vector<AudioRoute> routes;
-        ScopedAStatus status = module->getAudioRoutesForAudioPort(portId, &routes);
-        EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status;
+        EXPECT_IS_OK(module->getAudioRoutesForAudioPort(portId, &routes));
         for (const auto& r : routes) {
             if (r.sinkPortId != portId) {
                 const auto& srcs = r.sourcePortIds;
@@ -802,18 +742,14 @@
     }
     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;
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->getAudioRoutesForAudioPort(portId, &routes))
+                << "port ID " << portId;
     }
 }
 
 TEST_P(AudioCoreModule, CheckDevicePorts) {
     std::vector<AudioPort> ports;
-    {
-        ScopedAStatus status = module->getAudioPorts(&ports);
-        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
-    }
+    ASSERT_IS_OK(module->getAudioPorts(&ports));
     std::optional<int32_t> defaultOutput, defaultInput;
     std::set<AudioDevice> inputs, outputs;
     const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
@@ -859,17 +795,14 @@
 
 TEST_P(AudioCoreModule, CheckMixPorts) {
     std::vector<AudioPort> ports;
-    {
-        ScopedAStatus status = module->getAudioPorts(&ports);
-        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
-    }
+    ASSERT_IS_OK(module->getAudioPorts(&ports));
     std::optional<int32_t> primaryMixPort;
-    constexpr int primaryOutputFlag = 1 << static_cast<int>(AudioOutputFlags::PRIMARY);
     for (const auto& port : ports) {
         if (port.ext.getTag() != AudioPortExt::Tag::mix) continue;
         const auto& mixPort = port.ext.get<AudioPortExt::Tag::mix>();
         if (port.flags.getTag() == AudioIoFlags::Tag::output &&
-            ((port.flags.get<AudioIoFlags::Tag::output>() & primaryOutputFlag) != 0)) {
+            isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+                                 AudioOutputFlags::PRIMARY)) {
             EXPECT_FALSE(primaryMixPort.has_value())
                     << "At least two mix ports have PRIMARY flag set: " << primaryMixPort.value()
                     << " and " << port.id;
@@ -889,15 +822,13 @@
     }
     for (const auto portId : portIds) {
         AudioPort port;
-        ScopedAStatus status = module->getAudioPort(portId, &port);
-        EXPECT_EQ(EX_NONE, status.getExceptionCode()) << status;
+        EXPECT_IS_OK(module->getAudioPort(portId, &port));
         EXPECT_EQ(portId, port.id);
     }
     for (const auto portId : GetNonExistentIds(portIds)) {
         AudioPort port;
-        ScopedAStatus status = module->getAudioPort(portId, &port);
-        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
-                << status << " returned for port ID " << portId;
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->getAudioPort(portId, &port))
+                << "port ID " << portId;
     }
 }
 
@@ -929,9 +860,8 @@
                   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_IS_OK(module->getAudioPort(connectedPortId, &connectedPort))
+                << "port ID " << connectedPortId;
         EXPECT_EQ(portConnected.get(), connectedPort);
         const auto& portProfiles = connectedPort.profiles;
         EXPECT_NE(0UL, portProfiles.size())
@@ -944,10 +874,7 @@
                                                         << "profiles: " << connectedPort.toString();
 
         std::vector<AudioPort> allPorts;
-        {
-            ScopedAStatus status = module->getAudioPorts(&allPorts);
-            ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
-        }
+        ASSERT_IS_OK(module->getAudioPorts(&allPorts));
         const auto allPortsIt = findById(allPorts, connectedPortId);
         EXPECT_NE(allPorts.end(), allPortsIt);
         if (allPortsIt != allPorts.end()) {
@@ -965,9 +892,8 @@
             args.portConfigId = portConfigId;
             args.bufferSizeFrames = kDefaultBufferSizeFrames;
             aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
-            ScopedAStatus status = module->openInputStream(args, &ret);
-            EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
-                    << status << " openInputStream returned for port config ID " << portConfigId;
+            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openInputStream(args, &ret))
+                    << "port config ID " << portConfigId;
             EXPECT_EQ(nullptr, ret.stream);
         }
         {
@@ -975,9 +901,8 @@
             args.portConfigId = portConfigId;
             args.bufferSizeFrames = kDefaultBufferSizeFrames;
             aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
-            ScopedAStatus status = module->openOutputStream(args, &ret);
-            EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
-                    << status << " openOutputStream returned for port config ID " << portConfigId;
+            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
+                    << "port config ID " << portConfigId;
             EXPECT_EQ(nullptr, ret.stream);
         }
     }
@@ -992,10 +917,7 @@
     std::set<int32_t> portIds;
     ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
     std::vector<AudioPortConfig> portConfigs;
-    {
-        ScopedAStatus status = module->getAudioPortConfigs(&portConfigs);
-        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
-    }
+    ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigs));
     for (const auto& config : portConfigs) {
         EXPECT_EQ(1UL, portIds.count(config.portId))
                 << config.portId << " port id is unknown, config id " << config.id;
@@ -1006,9 +928,8 @@
     std::set<int32_t> portConfigIds;
     ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
     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;
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->resetAudioPortConfig(portConfigId))
+                << "port config ID " << portConfigId;
     }
 }
 
@@ -1016,21 +937,13 @@
 // the config does not delete it, but brings it back to the initial config.
 TEST_P(AudioCoreModule, ResetAudioPortConfigToInitialValue) {
     std::vector<AudioPortConfig> portConfigsBefore;
-    {
-        ScopedAStatus status = module->getAudioPortConfigs(&portConfigsBefore);
-        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
-    }
+    ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigsBefore));
     // TODO: Change port configs according to port profiles.
     for (const auto& c : portConfigsBefore) {
-        ScopedAStatus status = module->resetAudioPortConfig(c.id);
-        EXPECT_EQ(EX_NONE, status.getExceptionCode())
-                << status << " returned for port config ID " << c.id;
+        EXPECT_IS_OK(module->resetAudioPortConfig(c.id)) << "port config ID " << c.id;
     }
     std::vector<AudioPortConfig> portConfigsAfter;
-    {
-        ScopedAStatus status = module->getAudioPortConfigs(&portConfigsAfter);
-        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
-    }
+    ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigsAfter));
     for (const auto& c : portConfigsBefore) {
         auto afterIt = findById<AudioPortConfig>(portConfigsAfter, c.id);
         EXPECT_NE(portConfigsAfter.end(), afterIt)
@@ -1052,9 +965,8 @@
     portConfig.portId = srcMixPort.value().id;
     {
         bool applied = true;
-        ScopedAStatus status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
-        ASSERT_EQ(EX_NONE, status.getExceptionCode())
-                << status << "; Config: " << portConfig.toString();
+        ASSERT_IS_OK(module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
+                << "Config: " << portConfig.toString();
         EXPECT_FALSE(applied);
     }
     EXPECT_EQ(0, suggestedConfig.id);
@@ -1108,9 +1020,9 @@
         AudioPortConfig portConfig, suggestedConfig;
         bool applied;
         portConfig.portId = portId;
-        ScopedAStatus status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
-        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
-                << status << " returned for port ID " << portId;
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                      module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
+                << "port ID " << portId;
         EXPECT_FALSE(suggestedConfig.format.has_value());
         EXPECT_FALSE(suggestedConfig.channelMask.has_value());
         EXPECT_FALSE(suggestedConfig.sampleRate.has_value());
@@ -1124,9 +1036,9 @@
         AudioPortConfig portConfig, suggestedConfig;
         bool applied;
         portConfig.id = portConfigId;
-        ScopedAStatus status = module->setAudioPortConfig(portConfig, &suggestedConfig, &applied);
-        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
-                << status << " returned for port config ID " << portConfigId;
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                      module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
+                << "port config ID " << portConfigId;
         EXPECT_FALSE(suggestedConfig.format.has_value());
         EXPECT_FALSE(suggestedConfig.channelMask.has_value());
         EXPECT_FALSE(suggestedConfig.sampleRate.has_value());
@@ -1147,9 +1059,8 @@
         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();
+        EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored))
+                << "static port " << portWithData.toString();
     }
 }
 
@@ -1163,10 +1074,8 @@
     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";
+    EXPECT_STATUS(EX_ILLEGAL_STATE, module->setModuleDebug(midwayDebugChange))
+            << "when trying to disable connections simulation while having a connected device";
 }
 
 TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceInvalidPorts) {
@@ -1176,40 +1085,28 @@
     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";
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(invalidPort, &ignored))
+                << "port ID " << portId << ", when setting CONNECTED state";
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(portId))
+                << "port ID " << portId << ", when setting DISCONNECTED state";
     }
 
     std::vector<AudioPort> ports;
-    {
-        ScopedAStatus status = module->getAudioPorts(&ports);
-        ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
-    }
+    ASSERT_IS_OK(module->getAudioPorts(&ports));
     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";
+            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
+                    << "non-device port ID " << port.id << " when setting CONNECTED state";
+            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
+                    << "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
+                EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
+                        << "for a 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
+                EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
+                        << "for a permanently attached device port ID " << port.id
                         << " when setting DISCONNECTED state";
             }
         }
@@ -1225,27 +1122,22 @@
         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;
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
+                << "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 "
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                      module->connectExternalDevice(portConnected.get(), &ignored))
+                << "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();
-        }
+        EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored))
+                << "when connecting again the external device "
+                << portWithData.ext.get<AudioPortExt::Tag::device>().device.toString()
+                << "; Returned connected port " << ignored.toString() << " for template "
+                << portWithData.toString();
     }
 }
 
@@ -1266,9 +1158,8 @@
             // 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
+            EXPECT_STATUS(EX_ILLEGAL_STATE, module->disconnectExternalDevice(portConnected.getId()))
+                    << "when trying to disconnect device port ID " << port.id
                     << " with active configuration " << config.getId();
         }
     }
@@ -1282,10 +1173,7 @@
     }
     for (const auto& port : ports) {
         std::vector<AudioRoute> routesBefore;
-        {
-            ScopedAStatus status = module->getAudioRoutes(&routesBefore);
-            ASSERT_EQ(EX_NONE, status.getExceptionCode()) << status;
-        }
+        ASSERT_IS_OK(module->getAudioRoutes(&routesBefore));
 
         int32_t connectedPortId;
         {
@@ -1293,34 +1181,24 @@
             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;
-            }
+            ASSERT_IS_OK(module->getAudioRoutesForAudioPort(connectedPortId, &connectedPortRoutes))
+                    << "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;
+                ASSERT_IS_OK(module->getAudioRoutes(&allRoutes));
                 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;
+        ASSERT_STATUS(EX_ILLEGAL_ARGUMENT,
+                      module->getAudioRoutesForAudioPort(connectedPortId, &ignored))
+                << "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_IS_OK(module->getAudioRoutes(&routesAfter));
         ASSERT_EQ(routesBefore.size(), routesAfter.size())
                 << "Sizes of audio route arrays do not match after creating and "
                 << "releasing a connected port";
@@ -1333,8 +1211,6 @@
 template <typename Stream>
 class AudioStream : public AudioCoreModule {
   public:
-    static std::string direction(bool capitalize);
-
     void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp());
         ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
@@ -1351,9 +1227,7 @@
             ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
             heldStream = stream.getSharedPointer();
         }
-        ScopedAStatus status = heldStream->close();
-        EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
-                << status << " when closing the stream twice";
+        EXPECT_STATUS(EX_ILLEGAL_STATE, heldStream->close()) << "when closing the stream twice";
     }
 
     void OpenAllConfigs() {
@@ -1375,10 +1249,8 @@
         // The buffer size of 1 frame should be impractically small, and thus
         // less than any minimum buffer size suggested by any HAL.
         for (long bufferSize : std::array<long, 4>{-1, 0, 1, std::numeric_limits<long>::max()}) {
-            ScopedAStatus status = stream.SetUpNoChecks(module.get(), bufferSize);
-            EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
-                    << status << " open" << direction(true) << "Stream returned for " << bufferSize
-                    << " buffer size";
+            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.SetUpNoChecks(module.get(), bufferSize))
+                    << "for the buffer size " << bufferSize;
             EXPECT_EQ(nullptr, stream.get());
         }
     }
@@ -1392,10 +1264,9 @@
         }
         WithStream<Stream> stream(portConfig.value());
         ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
-        ScopedAStatus status = stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames);
-        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
-                << status << " open" << direction(true) << "Stream returned for port config ID "
-                << stream.getPortId();
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                      stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
+                << "port config ID " << stream.getPortId();
         EXPECT_EQ(nullptr, stream.get());
     }
 
@@ -1424,18 +1295,15 @@
                     ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
                 } else {
                     ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
-                    ScopedAStatus status =
-                            stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames);
-                    EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
-                            << status << " open" << direction(true)
-                            << "Stream returned for port config ID " << stream.getPortId()
-                            << ", maxOpenStreamCount is " << maxStreamCount;
+                    EXPECT_STATUS(EX_ILLEGAL_STATE,
+                                  stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
+                            << "port config ID " << stream.getPortId() << ", maxOpenStreamCount is "
+                            << maxStreamCount;
                 }
             }
         }
         if (!hasSingleRun) {
-            GTEST_SKIP() << "Not enough " << direction(false)
-                         << " ports to test max open stream count";
+            GTEST_SKIP() << "Not enough ports to test max open stream count";
         }
     }
 
@@ -1447,14 +1315,15 @@
         EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
     }
 
-    void ReadOrWrite(bool useImpl2, bool testObservablePosition) {
+    void ReadOrWrite(bool useSetupSequence2, bool validateObservablePosition) {
         const auto allPortConfigs =
                 moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
         if (allPortConfigs.empty()) {
             GTEST_SKIP() << "No mix ports have attached devices";
         }
         for (const auto& portConfig : allPortConfigs) {
-            EXPECT_NO_FATAL_FAILURE(ReadOrWriteImpl(portConfig, useImpl2, testObservablePosition))
+            EXPECT_NO_FATAL_FAILURE(
+                    ReadOrWriteImpl(portConfig, useSetupSequence2, validateObservablePosition))
                     << portConfig.toString();
         }
     }
@@ -1466,9 +1335,8 @@
         }
         WithStream<Stream> stream(portConfig.value());
         ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-        ScopedAStatus status = module->resetAudioPortConfig(stream.getPortId());
-        EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
-                << status << " returned for port config ID " << stream.getPortId();
+        EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(stream.getPortId()))
+                << "port config ID " << stream.getPortId();
     }
 
     void SendInvalidCommand() {
@@ -1483,11 +1351,10 @@
         WithStream<Stream> stream1(portConfig);
         ASSERT_NO_FATAL_FAILURE(stream1.SetUp(module.get(), kDefaultBufferSizeFrames));
         WithStream<Stream> stream2;
-        ScopedAStatus status = stream2.SetUpNoChecks(module.get(), stream1.getPortConfig(),
-                                                     kDefaultBufferSizeFrames);
-        EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
-                << status << " when opening " << direction(false)
-                << " stream twice for the same port config ID " << stream1.getPortId();
+        EXPECT_STATUS(EX_ILLEGAL_STATE, stream2.SetUpNoChecks(module.get(), stream1.getPortConfig(),
+                                                              kDefaultBufferSizeFrames))
+                << "when opening a stream twice for the same port config ID "
+                << stream1.getPortId();
     }
 
     template <class Worker>
@@ -1510,17 +1377,20 @@
         EXPECT_GT(frames, framesInitial);
     }
 
-    void ReadOrWriteImpl(const AudioPortConfig& portConfig, bool useImpl2,
-                         bool testObservablePosition) {
-        if (!useImpl2) {
-            ASSERT_NO_FATAL_FAILURE(ReadOrWriteImpl1(portConfig, testObservablePosition));
+    void ReadOrWriteImpl(const AudioPortConfig& portConfig, bool useSetupSequence2,
+                         bool validateObservablePosition) {
+        if (!useSetupSequence2) {
+            ASSERT_NO_FATAL_FAILURE(
+                    ReadOrWriteSetupSequence1(portConfig, validateObservablePosition));
         } else {
-            ASSERT_NO_FATAL_FAILURE(ReadOrWriteImpl2(portConfig, testObservablePosition));
+            ASSERT_NO_FATAL_FAILURE(
+                    ReadOrWriteSetupSequence2(portConfig, validateObservablePosition));
         }
     }
 
     // Set up a patch first, then open a stream.
-    void ReadOrWriteImpl1(const AudioPortConfig& portConfig, bool testObservablePosition) {
+    void ReadOrWriteSetupSequence1(const AudioPortConfig& portConfig,
+                                   bool validateObservablePosition) {
         auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
                 IOTraits<Stream>::is_input, portConfig);
         ASSERT_FALSE(devicePorts.empty());
@@ -1534,13 +1404,14 @@
 
         ASSERT_TRUE(worker.start());
         ASSERT_TRUE(worker.waitForAtLeastOneCycle());
-        if (testObservablePosition) {
+        if (validateObservablePosition) {
             ASSERT_NO_FATAL_FAILURE(WaitForObservablePositionAdvance(worker));
         }
     }
 
     // Open a stream, then set up a patch for it.
-    void ReadOrWriteImpl2(const AudioPortConfig& portConfig, bool testObservablePosition) {
+    void ReadOrWriteSetupSequence2(const AudioPortConfig& portConfig,
+                                   bool validateObservablePosition) {
         WithStream<Stream> stream(portConfig);
         ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
         typename IOTraits<Stream>::Worker worker(*stream.getContext());
@@ -1554,7 +1425,7 @@
 
         ASSERT_TRUE(worker.start());
         ASSERT_TRUE(worker.waitForAtLeastOneCycle());
-        if (testObservablePosition) {
+        if (validateObservablePosition) {
             ASSERT_NO_FATAL_FAILURE(WaitForObservablePositionAdvance(worker));
         }
     }
@@ -1583,15 +1454,6 @@
 using AudioStreamIn = AudioStream<IStreamIn>;
 using AudioStreamOut = AudioStream<IStreamOut>;
 
-template <>
-std::string AudioStreamIn::direction(bool capitalize) {
-    return capitalize ? "Input" : "input";
-}
-template <>
-std::string AudioStreamOut::direction(bool capitalize) {
-    return capitalize ? "Output" : "output";
-}
-
 #define TEST_IO_STREAM(method_name)                                                \
     TEST_P(AudioStreamIn, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); } \
     TEST_P(AudioStreamOut, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); }
@@ -1609,19 +1471,24 @@
 TEST_IO_STREAM(OpenInvalidDirection);
 TEST_IO_STREAM(OpenOverMaxCount);
 TEST_IO_STREAM(OpenTwiceSamePortConfig);
-TEST_IO_STREAM_2(ReadOrWrite, false, false);
-TEST_IO_STREAM_2(ReadOrWrite, true, false);
-TEST_IO_STREAM_2(ReadOrWrite, false, true);
-TEST_IO_STREAM_2(ReadOrWrite, true, true);
+// Use of constants makes comprehensible test names.
+constexpr bool SetupSequence1 = false;
+constexpr bool SetupSequence2 = true;
+constexpr bool SetupOnly = false;
+constexpr bool ValidateObservablePosition = true;
+TEST_IO_STREAM_2(ReadOrWrite, SetupSequence1, SetupOnly);
+TEST_IO_STREAM_2(ReadOrWrite, SetupSequence2, SetupOnly);
+TEST_IO_STREAM_2(ReadOrWrite, SetupSequence1, ValidateObservablePosition);
+TEST_IO_STREAM_2(ReadOrWrite, SetupSequence2, ValidateObservablePosition);
 TEST_IO_STREAM(ResetPortConfigWithOpenStream);
 TEST_IO_STREAM(SendInvalidCommand);
 
 TEST_P(AudioStreamOut, OpenTwicePrimary) {
     const auto mixPorts = moduleConfig->getMixPorts(false);
     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;
+               isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+                                    AudioOutputFlags::PRIMARY);
     });
     if (primaryPortIt == mixPorts.end()) {
         GTEST_SKIP() << "No primary mix port";
@@ -1635,19 +1502,14 @@
 }
 
 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()) {
+    const auto offloadMixPorts =
+            moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, true /*singlePort*/);
+    if (offloadMixPorts.empty()) {
         GTEST_SKIP()
                 << "No mix port for compressed offload that could be routed to attached devices";
     }
-    const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, *offloadPortIt);
+    const auto portConfig =
+            moduleConfig->getSingleConfigForMixPort(false, *offloadMixPorts.begin());
     ASSERT_TRUE(portConfig.has_value())
             << "No profiles specified for the compressed offload mix port";
     StreamDescriptor descriptor;
@@ -1657,10 +1519,8 @@
     args.sourceMetadata = GenerateSourceMetadata(portConfig.value());
     args.bufferSizeFrames = kDefaultBufferSizeFrames;
     aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
-    ScopedAStatus status = module->openOutputStream(args, &ret);
-    EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
-            << status
-            << " returned when no offload info is provided for a compressed offload mix port";
+    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
+            << "when no offload info is provided for a compressed offload mix port";
 }
 
 // Tests specific to audio patches. The fixure class is named 'AudioModulePatch'
@@ -1681,9 +1541,8 @@
         AudioPatch patch;
         patch.sourcePortConfigIds = sources;
         patch.sinkPortConfigIds = sinks;
-        ScopedAStatus status = module->setAudioPatch(patch, &patch);
-        ASSERT_EQ(expectedException, status.getExceptionCode())
-                << status << ": patch source ids: " << android::internal::ToString(sources)
+        ASSERT_STATUS(expectedException, module->setAudioPatch(patch, &patch))
+                << "patch source ids: " << android::internal::ToString(sources)
                 << "; sink ids: " << android::internal::ToString(sinks);
     }
 
@@ -1701,9 +1560,8 @@
                                           patch.get().sinkPortConfigIds.begin(),
                                           patch.get().sinkPortConfigIds.end());
         for (const auto portConfigId : sourceAndSinkPortConfigIds) {
-            ScopedAStatus status = module->resetAudioPortConfig(portConfigId);
-            EXPECT_EQ(EX_ILLEGAL_STATE, status.getExceptionCode())
-                    << status << " returned for port config ID " << portConfigId;
+            EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(portConfigId))
+                    << "port config ID " << portConfigId;
         }
     }
 
@@ -1748,10 +1606,8 @@
         }
         WithAudioPatch patch(srcSinkPair.value().first, srcSinkPair.value().second);
         ASSERT_NO_FATAL_FAILURE(patch.SetUpPortConfigs(module.get()));
-        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 "
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, patch.SetUpNoChecks(module.get()))
+                << "when setting up a patch from " << srcSinkPair.value().first.toString() << " to "
                 << srcSinkPair.value().second.toString() << " that does not have a route";
     }
 
@@ -1807,10 +1663,9 @@
         for (const auto patchId : GetNonExistentIds(patchIds)) {
             AudioPatch patchWithNonExistendId = patch.get();
             patchWithNonExistendId.id = patchId;
-            ScopedAStatus status =
-                    module->setAudioPatch(patchWithNonExistendId, &patchWithNonExistendId);
-            EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
-                    << status << " returned for patch ID " << patchId;
+            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                          module->setAudioPatch(patchWithNonExistendId, &patchWithNonExistendId))
+                    << "patch ID " << patchId;
         }
     }
 };
@@ -1832,9 +1687,8 @@
     std::set<int32_t> patchIds;
     ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
     for (const auto patchId : GetNonExistentIds(patchIds)) {
-        ScopedAStatus status = module->resetAudioPatch(patchId);
-        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode())
-                << status << " returned for patch ID " << patchId;
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->resetAudioPatch(patchId))
+                << "patch ID " << patchId;
     }
 }
 
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index f70948c..8b5eb13 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -14,7 +14,11 @@
  * limitations under the License.
  */
 
+#include <memory>
 #include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
 
 #define LOG_TAG "VtsHalAudioEffect"
 
@@ -29,43 +33,88 @@
 #include <aidl/android/hardware/audio/effect/IFactory.h>
 
 #include "AudioHalBinderServiceUtil.h"
+#include "TestUtils.h"
 
 using namespace android;
 
 using ndk::ScopedAStatus;
 
 using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::IFactory;
 using aidl::android::media::audio::common::AudioUuid;
 
-namespace ndk {
-std::ostream& operator<<(std::ostream& str, const ScopedAStatus& status) {
-    str << status.getDescription();
-    return str;
-}
-}  // namespace ndk
-
-class EffectFactory : public testing::TestWithParam<std::string> {
+class EffectFactoryHelper {
   public:
-    void SetUp() override { ASSERT_NO_FATAL_FAILURE(ConnectToService()); }
+    explicit EffectFactoryHelper(const std::string& name) : mServiceName(name) {}
 
-    void TearDown() override {}
-
-    void ConnectToService() {
-        serviceName = GetParam();
-        factory = IFactory::fromBinder(binderUtil.connectToService(serviceName));
-        ASSERT_NE(factory, nullptr);
+    void ConnectToFactoryService() {
+        mEffectFactory = IFactory::fromBinder(binderUtil.connectToService(mServiceName));
+        ASSERT_NE(mEffectFactory, nullptr);
     }
 
-    void RestartService() {
-        ASSERT_NE(factory, nullptr);
-        factory = IFactory::fromBinder(binderUtil.restartService());
-        ASSERT_NE(factory, nullptr);
+    void RestartFactoryService() {
+        ASSERT_NE(mEffectFactory, nullptr);
+        mEffectFactory = IFactory::fromBinder(binderUtil.restartService());
+        ASSERT_NE(mEffectFactory, nullptr);
     }
 
-    std::shared_ptr<IFactory> factory;
-    std::string serviceName;
+    void QueryAllEffects() {
+        EXPECT_NE(mEffectFactory, nullptr);
+        EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, &mCompleteIds));
+    }
+
+    void QueryEffects(const std::optional<AudioUuid>& in_type,
+                      const std::optional<AudioUuid>& in_instance,
+                      std::vector<Descriptor::Identity>* _aidl_return) {
+        EXPECT_NE(mEffectFactory, nullptr);
+        EXPECT_IS_OK(mEffectFactory->queryEffects(in_type, in_instance, _aidl_return));
+        mIds = *_aidl_return;
+    }
+
+    void CreateEffects() {
+        EXPECT_NE(mEffectFactory, nullptr);
+        for (const auto& id : mIds) {
+            std::shared_ptr<IEffect> effect;
+            EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect));
+            EXPECT_NE(effect, nullptr) << id.toString();
+            mEffectIdMap[effect] = id;
+        }
+    }
+
+    void DestroyEffects() {
+        EXPECT_NE(mEffectFactory, nullptr);
+        for (const auto& it : mEffectIdMap) {
+            EXPECT_IS_OK(mEffectFactory->destroyEffect(it.first));
+        }
+        mEffectIdMap.clear();
+    }
+
+    std::shared_ptr<IFactory> GetFactory() { return mEffectFactory; }
+    const std::vector<Descriptor::Identity>& GetEffectIds() { return mIds; }
+    const std::vector<Descriptor::Identity>& GetCompleteEffectIdList() { return mCompleteIds; }
+    const std::unordered_map<std::shared_ptr<IEffect>, Descriptor::Identity>& GetEffectMap() {
+        return mEffectIdMap;
+    }
+
+  private:
+    std::shared_ptr<IFactory> mEffectFactory;
+    std::string mServiceName;
     AudioHalBinderServiceUtil binderUtil;
+    std::vector<Descriptor::Identity> mIds;
+    std::vector<Descriptor::Identity> mCompleteIds;
+    std::unordered_map<std::shared_ptr<IEffect>, Descriptor::Identity> mEffectIdMap;
+};
+
+/// Effect factory testing.
+class EffectFactoryTest : public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override { ASSERT_NO_FATAL_FAILURE(mFactory.ConnectToFactoryService()); }
+
+    void TearDown() override { mFactory.DestroyEffects(); }
+
+    EffectFactoryHelper mFactory = EffectFactoryHelper(GetParam());
+
     // TODO: these UUID can get from config file
     // ec7178ec-e5e1-4432-a3f4-4657e6795210
     const AudioUuid nullUuid = {static_cast<int32_t>(0xec7178ec),
@@ -77,25 +126,23 @@
             static_cast<int32_t>(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
 };
 
-TEST_P(EffectFactory, SetupAndTearDown) {
+TEST_P(EffectFactoryTest, SetupAndTearDown) {
     // Intentionally empty test body.
 }
 
-TEST_P(EffectFactory, CanBeRestarted) {
-    ASSERT_NO_FATAL_FAILURE(RestartService());
+TEST_P(EffectFactoryTest, CanBeRestarted) {
+    ASSERT_NO_FATAL_FAILURE(mFactory.RestartFactoryService());
 }
 
-TEST_P(EffectFactory, QueriedDescriptorList) {
+TEST_P(EffectFactoryTest, QueriedDescriptorList) {
     std::vector<Descriptor::Identity> descriptors;
-    ScopedAStatus status = factory->queryEffects(std::nullopt, std::nullopt, &descriptors);
-    EXPECT_EQ(EX_NONE, status.getExceptionCode());
-    EXPECT_NE(static_cast<int>(descriptors.size()), 0);
+    mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
+    EXPECT_NE(descriptors.size(), 0UL);
 }
 
-TEST_P(EffectFactory, DescriptorUUIDNotNull) {
+TEST_P(EffectFactoryTest, DescriptorUUIDNotNull) {
     std::vector<Descriptor::Identity> descriptors;
-    ScopedAStatus status = factory->queryEffects(std::nullopt, std::nullopt, &descriptors);
-    EXPECT_EQ(EX_NONE, status.getExceptionCode());
+    mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
     // TODO: Factory eventually need to return the full list of MUST supported AOSP effects.
     for (auto& desc : descriptors) {
         EXPECT_NE(desc.type, zeroUuid);
@@ -103,28 +150,167 @@
     }
 }
 
-TEST_P(EffectFactory, QueriedDescriptorNotExistType) {
+TEST_P(EffectFactoryTest, QueriedDescriptorNotExistType) {
     std::vector<Descriptor::Identity> descriptors;
-    ScopedAStatus status = factory->queryEffects(nullUuid, std::nullopt, &descriptors);
-    EXPECT_EQ(EX_NONE, status.getExceptionCode());
-    EXPECT_EQ(static_cast<int>(descriptors.size()), 0);
+    mFactory.QueryEffects(nullUuid, std::nullopt, &descriptors);
+    EXPECT_EQ(descriptors.size(), 0UL);
 }
 
-TEST_P(EffectFactory, QueriedDescriptorNotExistInstance) {
+TEST_P(EffectFactoryTest, QueriedDescriptorNotExistInstance) {
     std::vector<Descriptor::Identity> descriptors;
-    ScopedAStatus status = factory->queryEffects(std::nullopt, nullUuid, &descriptors);
-    EXPECT_EQ(EX_NONE, status.getExceptionCode());
-    EXPECT_EQ(static_cast<int>(descriptors.size()), 0);
+    mFactory.QueryEffects(std::nullopt, nullUuid, &descriptors);
+    EXPECT_EQ(descriptors.size(), 0UL);
 }
 
-INSTANTIATE_TEST_SUITE_P(EffectFactoryTest, EffectFactory,
+TEST_P(EffectFactoryTest, CreateAndDestroyRepeat) {
+    std::vector<Descriptor::Identity> descriptors;
+    mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
+    auto numIds = mFactory.GetEffectIds().size();
+    EXPECT_NE(numIds, 0UL);
+
+    EXPECT_EQ(mFactory.GetEffectMap().size(), 0UL);
+    mFactory.CreateEffects();
+    EXPECT_EQ(mFactory.GetEffectMap().size(), numIds);
+    mFactory.DestroyEffects();
+    EXPECT_EQ(mFactory.GetEffectMap().size(), 0UL);
+
+    // Create and destroy again
+    mFactory.CreateEffects();
+    EXPECT_EQ(mFactory.GetEffectMap().size(), numIds);
+    mFactory.DestroyEffects();
+    EXPECT_EQ(mFactory.GetEffectMap().size(), 0UL);
+}
+
+TEST_P(EffectFactoryTest, CreateMultipleInstanceOfSameEffect) {
+    std::vector<Descriptor::Identity> descriptors;
+    mFactory.QueryEffects(std::nullopt, std::nullopt, &descriptors);
+    auto numIds = mFactory.GetEffectIds().size();
+    EXPECT_NE(numIds, 0UL);
+
+    EXPECT_EQ(mFactory.GetEffectMap().size(), 0UL);
+    mFactory.CreateEffects();
+    EXPECT_EQ(mFactory.GetEffectMap().size(), numIds);
+    // Create effect instances of same implementation
+    mFactory.CreateEffects();
+    EXPECT_EQ(mFactory.GetEffectMap().size(), 2 * numIds);
+
+    mFactory.CreateEffects();
+    EXPECT_EQ(mFactory.GetEffectMap().size(), 3 * numIds);
+
+    mFactory.DestroyEffects();
+    EXPECT_EQ(mFactory.GetEffectMap().size(), 0UL);
+}
+
+INSTANTIATE_TEST_SUITE_P(EffectFactoryTest, EffectFactoryTest,
                          testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
                          android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EffectFactory);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EffectFactoryTest);
+
+/// Effect testing.
+class AudioEffect : public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(mFactory.ConnectToFactoryService());
+        ASSERT_NO_FATAL_FAILURE(mFactory.CreateEffects());
+    }
+
+    void TearDown() override {
+        CloseEffects();
+        ASSERT_NO_FATAL_FAILURE(mFactory.DestroyEffects());
+    }
+
+    void OpenEffects() {
+        auto open = [](const std::shared_ptr<IEffect>& effect) { EXPECT_IS_OK(effect->open()); };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(open));
+    }
+
+    void CloseEffects() {
+        auto close = [](const std::shared_ptr<IEffect>& effect) { EXPECT_IS_OK(effect->close()); };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(close));
+    }
+
+    void GetEffectDescriptors() {
+        auto get = [](const std::shared_ptr<IEffect>& effect) {
+            Descriptor desc;
+            EXPECT_IS_OK(effect->getDescriptor(&desc));
+        };
+        EXPECT_NO_FATAL_FAILURE(ForEachEffect(get));
+    }
+
+    template <typename Functor>
+    void ForEachEffect(Functor functor) {
+        auto effectMap = mFactory.GetEffectMap();
+        for (const auto& it : effectMap) {
+            SCOPED_TRACE(it.second.toString());
+            functor(it.first);
+        }
+    }
+
+    EffectFactoryHelper mFactory = EffectFactoryHelper(GetParam());
+};
+
+TEST_P(AudioEffect, OpenEffectTest) {
+    EXPECT_NO_FATAL_FAILURE(OpenEffects());
+}
+
+TEST_P(AudioEffect, OpenAndCloseEffect) {
+    EXPECT_NO_FATAL_FAILURE(OpenEffects());
+    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+}
+
+TEST_P(AudioEffect, CloseUnopenedEffectTest) {
+    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+}
+
+TEST_P(AudioEffect, DoubleOpenCloseEffects) {
+    EXPECT_NO_FATAL_FAILURE(OpenEffects());
+    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    EXPECT_NO_FATAL_FAILURE(OpenEffects());
+    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+
+    EXPECT_NO_FATAL_FAILURE(OpenEffects());
+    EXPECT_NO_FATAL_FAILURE(OpenEffects());
+    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+
+    EXPECT_NO_FATAL_FAILURE(OpenEffects());
+    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+    EXPECT_NO_FATAL_FAILURE(CloseEffects());
+}
+
+TEST_P(AudioEffect, GetDescriptors) {
+    EXPECT_NO_FATAL_FAILURE(GetEffectDescriptors());
+}
+
+TEST_P(AudioEffect, DescriptorIdExistAndUnique) {
+    auto checker = [&](const std::shared_ptr<IEffect>& effect) {
+        Descriptor desc;
+        std::vector<Descriptor::Identity> idList;
+        EXPECT_IS_OK(effect->getDescriptor(&desc));
+        mFactory.QueryEffects(desc.common.id.type, desc.common.id.uuid, &idList);
+        EXPECT_EQ(idList.size(), 1UL);
+    };
+    EXPECT_NO_FATAL_FAILURE(ForEachEffect(checker));
+
+    // Check unique with a set
+    auto stringHash = [](const Descriptor::Identity& id) {
+        return std::hash<std::string>()(id.toString());
+    };
+    auto vec = mFactory.GetCompleteEffectIdList();
+    std::unordered_set<Descriptor::Identity, decltype(stringHash)> idSet(0, stringHash);
+    for (auto it : vec) {
+        EXPECT_EQ(idSet.count(it), 0UL);
+        idSet.insert(it);
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(AudioEffectTest, AudioEffect,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioEffect);
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
     ABinderProcess_setThreadPoolMaxThreadCount(1);
     ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
-}
+}
\ No newline at end of file
diff --git a/audio/common/all-versions/default/7.0/HidlUtils.cpp b/audio/common/all-versions/default/7.0/HidlUtils.cpp
index 0fd2947..f89c898 100644
--- a/audio/common/all-versions/default/7.0/HidlUtils.cpp
+++ b/audio/common/all-versions/default/7.0/HidlUtils.cpp
@@ -898,7 +898,7 @@
     for (const auto& transport : transports) {
         switch (transport.audioCapability.getDiscriminator()) {
             case AudioTransport::AudioCapability::hidl_discriminator::profile:
-                if (halPort->num_audio_profiles > AUDIO_PORT_MAX_AUDIO_PROFILES) {
+                if (halPort->num_audio_profiles >= AUDIO_PORT_MAX_AUDIO_PROFILES) {
                     ALOGE("%s, too many audio profiles", __func__);
                     result = BAD_VALUE;
                     break;
@@ -914,7 +914,8 @@
                                 result);
                 break;
             case AudioTransport::AudioCapability::hidl_discriminator::edid:
-                if (halPort->num_extra_audio_descriptors > AUDIO_PORT_MAX_EXTRA_AUDIO_DESCRIPTORS) {
+                if (halPort->num_extra_audio_descriptors >=
+                    AUDIO_PORT_MAX_EXTRA_AUDIO_DESCRIPTORS) {
                     ALOGE("%s, too many extra audio descriptors", __func__);
                     result = BAD_VALUE;
                     break;
diff --git a/audio/common/all-versions/default/tests/hidlutils_tests.cpp b/audio/common/all-versions/default/tests/hidlutils_tests.cpp
index e5ed844..93688fc 100644
--- a/audio/common/all-versions/default/tests/hidlutils_tests.cpp
+++ b/audio/common/all-versions/default/tests/hidlutils_tests.cpp
@@ -17,7 +17,6 @@
 #include <array>
 #include <string>
 
-#include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 
 #define LOG_TAG "HidlUtils_Test"
@@ -955,6 +954,18 @@
     EXPECT_TRUE(audio_port_configs_are_equal(&halConfig, &halConfigBack));
 }
 
+static AudioProfile generateValidAudioProfile() {
+    AudioProfile profile;
+    profile.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
+    profile.sampleRates.resize(2);
+    profile.sampleRates[0] = 44100;
+    profile.sampleRates[1] = 48000;
+    profile.channelMasks.resize(2);
+    profile.channelMasks[0] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO);
+    profile.channelMasks[1] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
+    return profile;
+}
+
 TEST(HidlUtils, ConvertInvalidAudioTransports) {
     hidl_vec<AudioTransport> invalid;
     struct audio_port_v7 halInvalid = {};
@@ -974,20 +985,32 @@
     invalid[0].audioCapability.edid(hidl_vec<uint8_t>(EXTRA_AUDIO_DESCRIPTOR_SIZE + 1));
     invalid[1].encapsulationType = "random string";
     EXPECT_EQ(BAD_VALUE, HidlUtils::audioTransportsToHal(invalid, &halInvalid));
+
+    // The size of audio profile must not be greater than the maximum value.
+    invalid.resize(0);
+    invalid.resize(AUDIO_PORT_MAX_AUDIO_PROFILES + 1);
+    for (size_t i = 0; i < invalid.size(); ++i) {
+        invalid[i].audioCapability.profile(generateValidAudioProfile());
+        invalid[i].encapsulationType =
+                toString(xsd::AudioEncapsulationType::AUDIO_ENCAPSULATION_TYPE_NONE);
+    }
+    EXPECT_EQ(BAD_VALUE, HidlUtils::audioTransportsToHal(invalid, &halInvalid));
+
+    // The size of extra audio descriptors must not be greater than the maximum value.
+    invalid.resize(0);
+    invalid.resize(AUDIO_PORT_MAX_EXTRA_AUDIO_DESCRIPTORS + 1);
+    for (size_t i = 0; i < invalid.size(); ++i) {
+        invalid[i].audioCapability.edid({0x11, 0x06, 0x01});
+        invalid[i].encapsulationType =
+                toString(xsd::AudioEncapsulationType::AUDIO_ENCAPSULATION_TYPE_IEC61937);
+    }
+    EXPECT_EQ(BAD_VALUE, HidlUtils::audioTransportsToHal(invalid, &halInvalid));
 }
 
 TEST(HidlUtils, ConvertAudioTransports) {
     hidl_vec<AudioTransport> transports;
     transports.resize(2);
-    AudioProfile profile;
-    profile.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
-    profile.sampleRates.resize(2);
-    profile.sampleRates[0] = 44100;
-    profile.sampleRates[1] = 48000;
-    profile.channelMasks.resize(2);
-    profile.channelMasks[0] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO);
-    profile.channelMasks[1] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
-    transports[0].audioCapability.profile(profile);
+    transports[0].audioCapability.profile(generateValidAudioProfile());
     hidl_vec<uint8_t> shortAudioDescriptor({0x11, 0x06, 0x01});
     transports[0].encapsulationType =
             toString(xsd::AudioEncapsulationType::AUDIO_ENCAPSULATION_TYPE_NONE);
@@ -1101,12 +1124,15 @@
 TYPED_TEST_SUITE(FilterTest, FilterTestTypeParams);
 
 TYPED_TEST(FilterTest, FilterOutNonVendorTags) {
-    SKIP_WITH_HWASAN; // b/230535046
     TypeParam emptyTags;
     EXPECT_EQ(emptyTags, HidlUtils::filterOutNonVendorTags(emptyTags));
 
-    TypeParam allVendorTags = {{"VX_GOOGLE_VR_42", "VX_GOOGLE_1E100"}};
-    EXPECT_EQ(allVendorTags, HidlUtils::filterOutNonVendorTags(allVendorTags));
+    // b/248421569, allocate two vendor tags at a time can run out of memory
+    // TypeParam allVendorTags = {{"VX_GOOGLE_VR_42", "VX_GOOGLE_1E100"}};
+    TypeParam allVendorTags1 = {{"VX_GOOGLE_VR_42"}};
+    EXPECT_EQ(allVendorTags1, HidlUtils::filterOutNonVendorTags(allVendorTags1));
+    TypeParam allVendorTags2 = {{"VX_GOOGLE_1E100"}};
+    EXPECT_EQ(allVendorTags2, HidlUtils::filterOutNonVendorTags(allVendorTags2));
 
     TypeParam oneVendorTag = {{"", "VX_GOOGLE_VR", "random_string"}};
     TypeParam oneVendorTagOnly = HidlUtils::filterOutNonVendorTags(oneVendorTag);
diff --git a/audio/policy/1.0/xml/api/current.txt b/audio/policy/1.0/xml/api/current.txt
index 0b77d45..84a2b71 100644
--- a/audio/policy/1.0/xml/api/current.txt
+++ b/audio/policy/1.0/xml/api/current.txt
@@ -217,6 +217,10 @@
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_GAME;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_MEDIA;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION;
+    enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED;
+    enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT;
+    enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST;
+    enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_EVENT;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_UNKNOWN;
     enum_constant public static final audio.policy.V1_0.UsageEnumType AUDIO_USAGE_VIRTUAL_SOURCE;
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 3ce12e7..b58a6c8 100644
--- a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
+++ b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
@@ -347,6 +347,11 @@
             <xs:enumeration value="AUDIO_USAGE_ALARM"/>
             <xs:enumeration value="AUDIO_USAGE_NOTIFICATION"/>
             <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE"/>
+            <!-- Note: the following 3 values were deprecated in Android T (13) SDK -->
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST"/>
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT"/>
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED"/>
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_EVENT"/>
             <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY"/>
             <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
             <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/>
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
index ebd728d..e9b74b7 100644
--- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -23,6 +23,7 @@
 #include <android/binder_process.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
+#include <cutils/properties.h>
 #include <fmq/AidlMessageQueue.h>
 
 #include <cstdint>
@@ -248,7 +249,8 @@
       case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
       case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
       case SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH: {
-        ASSERT_FALSE(temp_provider_capabilities_.empty());
+        // empty capability means offload is unsupported since capabilities are
+        // not hardcoded
         for (auto audio_capability : temp_provider_capabilities_) {
           ASSERT_EQ(audio_capability.getTag(),
                     AudioCapabilities::leAudioCapabilities);
@@ -513,8 +515,9 @@
         for (auto channel_mode : opus_capability->channelMode) {
           OpusConfiguration opus_data{
               .samplingFrequencyHz = samplingFrequencyHz,
+              .frameDurationUs = frameDurationUs,
               .channelMode = channel_mode,
-              .frameDurationUs = frameDurationUs};
+          };
           opus_codec_specifics.push_back(
               CodecConfiguration::CodecSpecific(opus_data));
         }
@@ -623,8 +626,8 @@
       for (auto channel_mode : a2dp_channel_modes) {
         PcmConfiguration pcm_config{
             .sampleRateHz = sample_rate,
-            .bitsPerSample = bits_per_sample,
             .channelMode = channel_mode,
+            .bitsPerSample = bits_per_sample,
         };
         bool is_codec_config_valid = IsPcmConfigSupported(pcm_config);
         DataMQDesc mq_desc;
@@ -937,8 +940,8 @@
       for (auto channel_mode : hearing_aid_channel_modes_) {
         PcmConfiguration pcm_config{
             .sampleRateHz = sample_rate,
-            .bitsPerSample = bits_per_sample,
             .channelMode = channel_mode,
+            .bitsPerSample = bits_per_sample,
         };
         bool is_codec_config_valid = IsPcmConfigSupported(pcm_config);
         DataMQDesc mq_desc;
@@ -1008,8 +1011,8 @@
         for (auto data_interval_us : le_audio_output_data_interval_us_) {
           PcmConfiguration pcm_config{
               .sampleRateHz = sample_rate,
-              .bitsPerSample = bits_per_sample,
               .channelMode = channel_mode,
+              .bitsPerSample = bits_per_sample,
               .dataIntervalUs = data_interval_us,
           };
           bool is_codec_config_valid =
@@ -1081,8 +1084,8 @@
         for (auto data_interval_us : le_audio_input_data_interval_us_) {
           PcmConfiguration pcm_config{
               .sampleRateHz = sample_rate,
-              .bitsPerSample = bits_per_sample,
               .channelMode = channel_mode,
+              .bitsPerSample = bits_per_sample,
               .dataIntervalUs = data_interval_us,
           };
           bool is_codec_config_valid =
@@ -1144,7 +1147,7 @@
                                                            bool supported) {
     std::vector<Lc3Configuration> le_audio_codec_configs;
     if (!supported) {
-      Lc3Configuration lc3_config{.samplingFrequencyHz = 0, .pcmBitDepth = 0};
+      Lc3Configuration lc3_config{.pcmBitDepth = 0, .samplingFrequencyHz = 0};
       le_audio_codec_configs.push_back(lc3_config);
       return le_audio_codec_configs;
     }
@@ -1428,8 +1431,8 @@
         for (auto data_interval_us : le_audio_output_data_interval_us_) {
           PcmConfiguration pcm_config{
               .sampleRateHz = sample_rate,
-              .bitsPerSample = bits_per_sample,
               .channelMode = channel_mode,
+              .bitsPerSample = bits_per_sample,
               .dataIntervalUs = data_interval_us,
           };
           bool is_codec_config_valid =
@@ -1490,7 +1493,7 @@
   std::vector<Lc3Configuration> GetBroadcastLc3SupportedList(bool supported) {
     std::vector<Lc3Configuration> le_audio_codec_configs;
     if (!supported) {
-      Lc3Configuration lc3_config{.samplingFrequencyHz = 0, .pcmBitDepth = 0};
+      Lc3Configuration lc3_config{.pcmBitDepth = 0, .samplingFrequencyHz = 0};
       le_audio_codec_configs.push_back(lc3_config);
       return le_audio_codec_configs;
     }
@@ -1650,8 +1653,8 @@
       for (auto channel_mode : a2dp_channel_modes) {
         PcmConfiguration pcm_config{
             .sampleRateHz = sample_rate,
-            .bitsPerSample = bits_per_sample,
             .channelMode = channel_mode,
+            .bitsPerSample = bits_per_sample,
         };
         bool is_codec_config_valid = IsPcmConfigSupported(pcm_config);
         DataMQDesc mq_desc;
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index d08cb0a..674dd11 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -40,9 +40,13 @@
         "aidl_session/BluetoothAudioCodecs.cpp",
         "aidl_session/BluetoothAudioSession.cpp",
         "aidl_session/HidlToAidlMiddleware.cpp",
+        "aidl_session/BluetoothLeAudioCodecsProvider.cpp",
     ],
     export_include_dirs: ["aidl_session/"],
-    header_libs: ["libhardware_headers"],
+    header_libs: [
+        "libhardware_headers",
+        "libxsdc-utils",
+    ],
     shared_libs: [
         "android.hardware.bluetooth.audio@2.0",
         "android.hardware.bluetooth.audio@2.1",
@@ -53,5 +57,15 @@
         "liblog",
         "android.hardware.bluetooth.audio-V2-ndk",
         "libhidlbase",
+        "libxml2",
     ],
+    generated_sources: ["le_audio_codec_capabilities"],
+    generated_headers: ["le_audio_codec_capabilities"],
+}
+
+xsd_config {
+    name: "le_audio_codec_capabilities",
+    srcs: ["le_audio_codec_capabilities/le_audio_codec_capabilities.xsd"],
+    package_name: "aidl.android.hardware.bluetooth.audio.setting",
+    api_dir: "le_audio_codec_capabilities/schema",
 }
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
index 036d6cd..855dd28 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -32,6 +32,8 @@
 #include <aidl/android/hardware/bluetooth/audio/SbcChannelMode.h>
 #include <android-base/logging.h>
 
+#include "BluetoothLeAudioCodecsProvider.h"
+
 namespace aidl {
 namespace android {
 namespace hardware {
@@ -96,67 +98,6 @@
 
 std::vector<LeAudioCodecCapabilitiesSetting> kDefaultOffloadLeAudioCapabilities;
 
-static const UnicastCapability kInvalidUnicastCapability = {
-    .codecType = CodecType::UNKNOWN};
-
-static const BroadcastCapability kInvalidBroadcastCapability = {
-    .codecType = CodecType::UNKNOWN};
-
-// Default Supported Codecs
-// LC3 16_1: sample rate: 16 kHz, frame duration: 7.5 ms, octets per frame: 30
-static const Lc3Capabilities kLc3Capability_16_1 = {
-    .samplingFrequencyHz = {16000},
-    .frameDurationUs = {7500},
-    .octetsPerFrame = {30}};
-
-// Default Supported Codecs
-// LC3 16_2: sample rate: 16 kHz, frame duration: 10 ms, octets per frame: 40
-static const Lc3Capabilities kLc3Capability_16_2 = {
-    .samplingFrequencyHz = {16000},
-    .frameDurationUs = {10000},
-    .octetsPerFrame = {40}};
-
-// Default Supported Codecs
-// LC3 24_2: sample rate: 24 kHz, frame duration: 10 ms, octets per frame: 60
-static const Lc3Capabilities kLc3Capability_24_2 = {
-    .samplingFrequencyHz = {24000},
-    .frameDurationUs = {10000},
-    .octetsPerFrame = {60}};
-
-// Default Supported Codecs
-// LC3 32_2: sample rate: 32 kHz, frame duration: 10 ms, octets per frame: 80
-static const Lc3Capabilities kLc3Capability_32_2 = {
-    .samplingFrequencyHz = {32000},
-    .frameDurationUs = {10000},
-    .octetsPerFrame = {80}};
-
-// Default Supported Codecs
-// LC3 48_4: sample rate: 48 kHz, frame duration: 10 ms, octets per frame: 120
-static const Lc3Capabilities kLc3Capability_48_4 = {
-    .samplingFrequencyHz = {48000},
-    .frameDurationUs = {10000},
-    .octetsPerFrame = {120}};
-
-static const std::vector<Lc3Capabilities> supportedLc3CapabilityList = {
-    kLc3Capability_48_4, kLc3Capability_32_2, kLc3Capability_24_2,
-    kLc3Capability_16_2, kLc3Capability_16_1};
-
-static AudioLocation stereoAudio = static_cast<AudioLocation>(
-    static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
-    static_cast<uint8_t>(AudioLocation::FRONT_RIGHT));
-static AudioLocation monoAudio = AudioLocation::UNKNOWN;
-
-// Stores the supported setting of audio location, connected device, and the
-// channel count for each device
-std::vector<std::tuple<AudioLocation, uint8_t, uint8_t>>
-    supportedDeviceSetting = {
-        // Stereo, two connected device, one for L one for R
-        std::make_tuple(stereoAudio, 2, 1),
-        // Stereo, one connected device for both L and R
-        std::make_tuple(stereoAudio, 1, 2),
-        // Mono
-        std::make_tuple(monoAudio, 1, 1)};
-
 template <class T>
 bool BluetoothAudioCodecs::ContainedInVector(
     const std::vector<T>& vector, const typename identity<T>::type& target) {
@@ -444,19 +385,6 @@
   return false;
 }
 
-UnicastCapability composeUnicastLc3Capability(
-    AudioLocation audioLocation, uint8_t deviceCnt, uint8_t channelCount,
-    const Lc3Capabilities& capability) {
-  return {
-      .codecType = CodecType::LC3,
-      .supportedChannel = audioLocation,
-      .deviceCount = deviceCnt,
-      .channelCountPerDevice = channelCount,
-      .leAudioCodecCapabilities =
-          UnicastCapability::LeAudioCodecCapabilities(capability),
-  };
-}
-
 std::vector<LeAudioCodecCapabilitiesSetting>
 BluetoothAudioCodecs::GetLeAudioOffloadCodecCapabilities(
     const SessionType& session_type) {
@@ -470,41 +398,8 @@
   }
 
   if (kDefaultOffloadLeAudioCapabilities.empty()) {
-    for (auto [audioLocation, deviceCnt, channelCount] :
-         supportedDeviceSetting) {
-      for (auto capability : supportedLc3CapabilityList) {
-        UnicastCapability lc3Capability = composeUnicastLc3Capability(
-            audioLocation, deviceCnt, channelCount, capability);
-        UnicastCapability lc3MonoDecodeCapability =
-            composeUnicastLc3Capability(monoAudio, 1, 1, capability);
-
-        // Adds the capability for encode only
-        kDefaultOffloadLeAudioCapabilities.push_back(
-            {.unicastEncodeCapability = lc3Capability,
-             .unicastDecodeCapability = kInvalidUnicastCapability,
-             .broadcastCapability = kInvalidBroadcastCapability});
-
-        // Adds the capability for decode only
-        kDefaultOffloadLeAudioCapabilities.push_back(
-            {.unicastEncodeCapability = kInvalidUnicastCapability,
-             .unicastDecodeCapability = lc3Capability,
-             .broadcastCapability = kInvalidBroadcastCapability});
-
-        // Adds the capability for the case that encode and decode exist at the
-        // same time(force one active device for decode)
-        kDefaultOffloadLeAudioCapabilities.push_back(
-            {.unicastEncodeCapability = lc3Capability,
-             .unicastDecodeCapability = lc3MonoDecodeCapability,
-             .broadcastCapability = kInvalidBroadcastCapability});
-
-        // Adds the capability for the case that encode and decode exist at the
-        // same time
-        kDefaultOffloadLeAudioCapabilities.push_back(
-            {.unicastEncodeCapability = lc3Capability,
-             .unicastDecodeCapability = lc3Capability,
-             .broadcastCapability = kInvalidBroadcastCapability});
-      }
-    }
+    kDefaultOffloadLeAudioCapabilities =
+        BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities();
   }
 
   return kDefaultOffloadLeAudioCapabilities;
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index 292d352..2b0caad 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -60,12 +60,14 @@
     LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
                << " MqDescriptor Invalid";
     audio_config_ = nullptr;
+    leaudio_connection_map_ = nullptr;
   } else {
     stack_iface_ = stack_iface;
     latency_modes_ = latency_modes;
     LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
               << ", AudioConfiguration=" << audio_config.toString();
     ReportSessionStatus();
+    is_streaming_ = false;
   }
 }
 
@@ -74,11 +76,13 @@
   bool toggled = IsSessionReady();
   LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
   audio_config_ = nullptr;
+  leaudio_connection_map_ = nullptr;
   stack_iface_ = nullptr;
   UpdateDataPath(nullptr);
   if (toggled) {
     ReportSessionStatus();
   }
+  is_streaming_ = false;
 }
 
 /***
@@ -106,18 +110,72 @@
   return *audio_config_;
 }
 
+const AudioConfiguration BluetoothAudioSession::GetLeAudioConnectionMap() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    return AudioConfiguration(LeAudioConfiguration{});
+  }
+  return *leaudio_connection_map_;
+}
+
 void BluetoothAudioSession::ReportAudioConfigChanged(
     const AudioConfiguration& audio_config) {
   if (session_type_ !=
           SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
       session_type_ !=
-          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH &&
-      session_type_ !=
-          SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
     return;
   }
+
   std::lock_guard<std::recursive_mutex> guard(mutex_);
-  audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
+  if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
+    LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
+               << toString(session_type_);
+    return;
+  }
+
+  if (is_streaming_) {
+    if (audio_config_ == nullptr) {
+      LOG(ERROR) << __func__ << " for SessionType=" << toString(session_type_)
+                 << " audio_config_ is nullptr during streaming. It shouldn't "
+                    "be happened";
+      return;
+    }
+
+    auto new_leaudio_config =
+        audio_config.get<AudioConfiguration::leAudioConfig>();
+    auto current_leaudio_config =
+        (*audio_config_).get<AudioConfiguration::leAudioConfig>();
+    if (new_leaudio_config.codecType != current_leaudio_config.codecType) {
+      LOG(ERROR)
+          << __func__ << " for SessionType=" << toString(session_type_)
+          << " codec type changed during streaming. It shouldn't be happened ";
+    }
+    auto new_lc3_config = new_leaudio_config.leAudioCodecConfig
+                              .get<LeAudioCodecConfiguration::lc3Config>();
+    auto current_lc3_config = current_leaudio_config.leAudioCodecConfig
+                                  .get<LeAudioCodecConfiguration::lc3Config>();
+    if ((new_lc3_config.pcmBitDepth != current_lc3_config.pcmBitDepth) ||
+        (new_lc3_config.samplingFrequencyHz !=
+         current_lc3_config.samplingFrequencyHz) ||
+        (new_lc3_config.frameDurationUs !=
+         current_lc3_config.frameDurationUs) ||
+        (new_lc3_config.octetsPerFrame != current_lc3_config.octetsPerFrame) ||
+        (new_lc3_config.blocksPerSdu != current_lc3_config.blocksPerSdu)) {
+      LOG(ERROR)
+          << __func__ << " for SessionType=" << toString(session_type_)
+          << " lc3 config changed during streaming. It shouldn't be happened";
+      return;
+    }
+
+    leaudio_connection_map_ =
+        std::make_unique<AudioConfiguration>(audio_config);
+  } else {
+    audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
+    leaudio_connection_map_ =
+        std::make_unique<AudioConfiguration>(audio_config);
+  }
+
   if (observers_.empty()) {
     LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
                  << " has NO port state observer";
@@ -129,7 +187,11 @@
     LOG(INFO) << __func__ << " for SessionType=" << toString(session_type_)
               << ", bluetooth_audio=0x"
               << ::android::base::StringPrintf("%04x", cookie);
-    if (cb->audio_configuration_changed_cb_ != nullptr) {
+    if (is_streaming_) {
+      if (cb->soft_audio_configuration_changed_cb_ != nullptr) {
+        cb->soft_audio_configuration_changed_cb_(cookie);
+      }
+    } else if (cb->audio_configuration_changed_cb_ != nullptr) {
       cb->audio_configuration_changed_cb_(cookie);
     }
   }
@@ -419,6 +481,12 @@
                  << " has NO port state observer";
     return;
   }
+  if (start_resp && status == BluetoothAudioStatus::SUCCESS) {
+    is_streaming_ = true;
+  } else if (!start_resp && (status == BluetoothAudioStatus::SUCCESS ||
+                             status == BluetoothAudioStatus::RECONFIGURATION)) {
+    is_streaming_ = false;
+  }
   for (auto& observer : observers_) {
     uint16_t cookie = observer.first;
     std::shared_ptr<PortStatusCallbacks> callback = observer.second;
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
index 5bf17bd..faf4ffb 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
@@ -102,6 +102,13 @@
    ***/
   std::function<void(uint16_t cookie, bool allowed)>
       low_latency_mode_allowed_cb_;
+  /***
+   * soft_audio_configuration_changed_cb_ - when the Bluetooth stack change
+   * the streamMap during the streaming, the BluetoothAudioProvider will invoke
+   * this callback to report to the bluetooth_audio module.
+   * @param: cookie - indicates which bluetooth_audio output should handle
+   ***/
+  std::function<void(uint16_t cookie)> soft_audio_configuration_changed_cb_;
 };
 
 class BluetoothAudioSession {
@@ -159,6 +166,12 @@
   const AudioConfiguration GetAudioConfig();
 
   /***
+   * The control function is for the bluetooth_audio module to get the current
+   * LE audio connection map
+   ***/
+  const AudioConfiguration GetLeAudioConnectionMap();
+
+  /***
    * The report function is used to report that the Bluetooth stack has notified
    * the audio configuration changed, and will invoke
    * audio_configuration_changed_cb_ to notify registered bluetooth_audio
@@ -206,8 +219,11 @@
   std::unique_ptr<DataMQ> data_mq_;
   // audio data configuration for both software and offloading
   std::unique_ptr<AudioConfiguration> audio_config_;
+  std::unique_ptr<AudioConfiguration> leaudio_connection_map_;
   std::vector<LatencyMode> latency_modes_;
   bool low_latency_allowed_ = true;
+  // saving those steaming state based on the session_type
+  bool is_streaming_ = false;
 
   // saving those registered bluetooth_audio's callbacks
   std::unordered_map<uint16_t, std::shared_ptr<struct PortStatusCallbacks>>
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
index 0782c82..881c6c1 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
@@ -95,6 +95,25 @@
   }
 
   /***
+   * The control API for the bluetooth_audio module to get current
+   * LE audio connection map
+   ***/
+  static const AudioConfiguration GetLeAudioConnectionMap(
+      const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if ((session_type ==
+             SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+         session_type ==
+             SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) &&
+        session_ptr != nullptr) {
+      return session_ptr->GetLeAudioConnectionMap();
+    }
+
+    return AudioConfiguration(LeAudioConfiguration{});
+  }
+
+  /***
    * Those control APIs for the bluetooth_audio module to start / suspend /
   stop
    * stream, to check position, and to update metadata.
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
new file mode 100644
index 0000000..bf49270
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BTAudioCodecsProviderAidl"
+
+#include "BluetoothLeAudioCodecsProvider.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+static const char* kLeAudioCodecCapabilitiesFile =
+    "/vendor/etc/le_audio_codec_capabilities.xml";
+
+static const AudioLocation kStereoAudio = static_cast<AudioLocation>(
+    static_cast<uint8_t>(AudioLocation::FRONT_LEFT) |
+    static_cast<uint8_t>(AudioLocation::FRONT_RIGHT));
+static const AudioLocation kMonoAudio = AudioLocation::UNKNOWN;
+
+static std::vector<LeAudioCodecCapabilitiesSetting> leAudioCodecCapabilities;
+
+std::vector<LeAudioCodecCapabilitiesSetting>
+BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities() {
+  if (!leAudioCodecCapabilities.empty()) {
+    return leAudioCodecCapabilities;
+  }
+
+  const auto le_audio_offload_setting =
+      setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile);
+  if (!le_audio_offload_setting.has_value()) {
+    LOG(ERROR) << __func__ << ": Failed to read "
+               << kLeAudioCodecCapabilitiesFile;
+    return {};
+  }
+
+  std::vector<setting::Scenario> supported_scenarios =
+      GetScenarios(le_audio_offload_setting);
+  if (supported_scenarios.empty()) {
+    LOG(ERROR) << __func__ << ": No scenarios in "
+               << kLeAudioCodecCapabilitiesFile;
+    return {};
+  }
+
+  UpdateConfigurationsToMap(le_audio_offload_setting);
+  if (configuration_map_.empty()) {
+    LOG(ERROR) << __func__ << ": No configurations in "
+               << kLeAudioCodecCapabilitiesFile;
+    return {};
+  }
+
+  UpdateCodecConfigurationsToMap(le_audio_offload_setting);
+  if (codec_configuration_map_.empty()) {
+    LOG(ERROR) << __func__ << ": No codec configurations in "
+               << kLeAudioCodecCapabilitiesFile;
+    return {};
+  }
+
+  UpdateStrategyConfigurationsToMap(le_audio_offload_setting);
+  if (strategy_configuration_map_.empty()) {
+    LOG(ERROR) << __func__ << ": No strategy configurations in "
+               << kLeAudioCodecCapabilitiesFile;
+    return {};
+  }
+
+  leAudioCodecCapabilities =
+      ComposeLeAudioCodecCapabilities(supported_scenarios);
+  return leAudioCodecCapabilities;
+}
+
+std::vector<setting::Scenario> BluetoothLeAudioCodecsProvider::GetScenarios(
+    const std::optional<setting::LeAudioOffloadSetting>&
+        le_audio_offload_setting) {
+  std::vector<setting::Scenario> supported_scenarios;
+  if (le_audio_offload_setting->hasScenarioList()) {
+    for (const auto& scenario_list :
+         le_audio_offload_setting->getScenarioList()) {
+      if (!scenario_list.hasScenario()) {
+        continue;
+      }
+      for (const auto& scenario : scenario_list.getScenario()) {
+        if (scenario.hasEncode() && scenario.hasDecode()) {
+          supported_scenarios.push_back(scenario);
+        }
+      }
+    }
+  }
+  return supported_scenarios;
+}
+
+void BluetoothLeAudioCodecsProvider::UpdateConfigurationsToMap(
+    const std::optional<setting::LeAudioOffloadSetting>&
+        le_audio_offload_setting) {
+  if (le_audio_offload_setting->hasConfigurationList()) {
+    for (const auto& configuration_list :
+         le_audio_offload_setting->getConfigurationList()) {
+      if (!configuration_list.hasConfiguration()) {
+        continue;
+      }
+      for (const auto& configuration : configuration_list.getConfiguration()) {
+        if (configuration.hasName() && configuration.hasCodecConfiguration() &&
+            configuration.hasStrategyConfiguration()) {
+          configuration_map_.insert(
+              make_pair(configuration.getName(), configuration));
+        }
+      }
+    }
+  }
+}
+
+void BluetoothLeAudioCodecsProvider::UpdateCodecConfigurationsToMap(
+    const std::optional<setting::LeAudioOffloadSetting>&
+        le_audio_offload_setting) {
+  if (le_audio_offload_setting->hasCodecConfigurationList()) {
+    for (const auto& codec_configuration_list :
+         le_audio_offload_setting->getCodecConfigurationList()) {
+      if (!codec_configuration_list.hasCodecConfiguration()) {
+        continue;
+      }
+      for (const auto& codec_configuration :
+           codec_configuration_list.getCodecConfiguration()) {
+        if (IsValidCodecConfiguration(codec_configuration)) {
+          codec_configuration_map_.insert(
+              make_pair(codec_configuration.getName(), codec_configuration));
+        }
+      }
+    }
+  }
+}
+
+void BluetoothLeAudioCodecsProvider::UpdateStrategyConfigurationsToMap(
+    const std::optional<setting::LeAudioOffloadSetting>&
+        le_audio_offload_setting) {
+  if (le_audio_offload_setting->hasStrategyConfigurationList()) {
+    for (const auto& strategy_configuration_list :
+         le_audio_offload_setting->getStrategyConfigurationList()) {
+      if (!strategy_configuration_list.hasStrategyConfiguration()) {
+        continue;
+      }
+      for (const auto& strategy_configuration :
+           strategy_configuration_list.getStrategyConfiguration()) {
+        if (IsValidStrategyConfiguration(strategy_configuration)) {
+          strategy_configuration_map_.insert(make_pair(
+              strategy_configuration.getName(), strategy_configuration));
+        }
+      }
+    }
+  }
+}
+
+std::vector<LeAudioCodecCapabilitiesSetting>
+BluetoothLeAudioCodecsProvider::ComposeLeAudioCodecCapabilities(
+    const std::vector<setting::Scenario>& supported_scenarios) {
+  std::vector<LeAudioCodecCapabilitiesSetting> le_audio_codec_capabilities;
+  for (const auto& scenario : supported_scenarios) {
+    UnicastCapability unicast_encode_capability =
+        GetUnicastCapability(scenario.getEncode());
+    UnicastCapability unicast_decode_capability =
+        GetUnicastCapability(scenario.getDecode());
+    // encode and decode cannot be unknown at the same time
+    if (unicast_encode_capability.codecType == CodecType::UNKNOWN &&
+        unicast_decode_capability.codecType == CodecType::UNKNOWN) {
+      continue;
+    }
+    BroadcastCapability broadcast_capability = {.codecType =
+                                                    CodecType::UNKNOWN};
+    le_audio_codec_capabilities.push_back(
+        {.unicastEncodeCapability = unicast_encode_capability,
+         .unicastDecodeCapability = unicast_decode_capability,
+         .broadcastCapability = broadcast_capability});
+  }
+  return le_audio_codec_capabilities;
+}
+
+UnicastCapability BluetoothLeAudioCodecsProvider::GetUnicastCapability(
+    const std::string& coding_direction) {
+  if (coding_direction == "invalid") {
+    return {.codecType = CodecType::UNKNOWN};
+  }
+
+  auto configuration_iter = configuration_map_.find(coding_direction);
+  if (configuration_iter == configuration_map_.end()) {
+    return {.codecType = CodecType::UNKNOWN};
+  }
+
+  auto codec_configuration_iter = codec_configuration_map_.find(
+      configuration_iter->second.getCodecConfiguration());
+  if (codec_configuration_iter == codec_configuration_map_.end()) {
+    return {.codecType = CodecType::UNKNOWN};
+  }
+
+  auto strategy_configuration_iter = strategy_configuration_map_.find(
+      configuration_iter->second.getStrategyConfiguration());
+  if (strategy_configuration_iter == strategy_configuration_map_.end()) {
+    return {.codecType = CodecType::UNKNOWN};
+  }
+
+  CodecType codec_type =
+      GetCodecType(codec_configuration_iter->second.getCodec());
+  if (codec_type == CodecType::LC3) {
+    return ComposeUnicastCapability(
+        codec_type,
+        GetAudioLocation(
+            strategy_configuration_iter->second.getAudioLocation()),
+        strategy_configuration_iter->second.getConnectedDevice(),
+        strategy_configuration_iter->second.getChannelCount(),
+        ComposeLc3Capability(codec_configuration_iter->second));
+  }
+  return {.codecType = CodecType::UNKNOWN};
+}
+
+template <class T>
+UnicastCapability BluetoothLeAudioCodecsProvider::ComposeUnicastCapability(
+    const CodecType& codec_type, const AudioLocation& audio_location,
+    const uint8_t& device_cnt, const uint8_t& channel_count,
+    const T& capability) {
+  return {
+      .codecType = codec_type,
+      .supportedChannel = audio_location,
+      .deviceCount = device_cnt,
+      .channelCountPerDevice = channel_count,
+      .leAudioCodecCapabilities =
+          UnicastCapability::LeAudioCodecCapabilities(capability),
+  };
+}
+
+Lc3Capabilities BluetoothLeAudioCodecsProvider::ComposeLc3Capability(
+    const setting::CodecConfiguration& codec_configuration) {
+  return {.samplingFrequencyHz = {codec_configuration.getSamplingFrequency()},
+          .frameDurationUs = {codec_configuration.getFrameDurationUs()},
+          .octetsPerFrame = {codec_configuration.getOctetsPerCodecFrame()}};
+}
+
+AudioLocation BluetoothLeAudioCodecsProvider::GetAudioLocation(
+    const setting::AudioLocation& audio_location) {
+  switch (audio_location) {
+    case setting::AudioLocation::MONO:
+      return kMonoAudio;
+    case setting::AudioLocation::STEREO:
+      return kStereoAudio;
+    default:
+      return AudioLocation::UNKNOWN;
+  }
+}
+
+CodecType BluetoothLeAudioCodecsProvider::GetCodecType(
+    const setting::CodecType& codec_type) {
+  switch (codec_type) {
+    case setting::CodecType::LC3:
+      return CodecType::LC3;
+    default:
+      return CodecType::UNKNOWN;
+  }
+}
+
+bool BluetoothLeAudioCodecsProvider::IsValidCodecConfiguration(
+    const setting::CodecConfiguration& codec_configuration) {
+  return codec_configuration.hasName() && codec_configuration.hasCodec() &&
+         codec_configuration.hasSamplingFrequency() &&
+         codec_configuration.hasFrameDurationUs() &&
+         codec_configuration.hasOctetsPerCodecFrame();
+}
+
+bool BluetoothLeAudioCodecsProvider::IsValidStrategyConfiguration(
+    const setting::StrategyConfiguration& strategy_configuration) {
+  if (!strategy_configuration.hasName() ||
+      !strategy_configuration.hasAudioLocation() ||
+      !strategy_configuration.hasConnectedDevice() ||
+      !strategy_configuration.hasChannelCount()) {
+    return false;
+  }
+  if (strategy_configuration.getAudioLocation() ==
+      setting::AudioLocation::STEREO) {
+    if ((strategy_configuration.getConnectedDevice() == 2 &&
+         strategy_configuration.getChannelCount() == 1) ||
+        (strategy_configuration.getConnectedDevice() == 1 &&
+         strategy_configuration.getChannelCount() == 2)) {
+      // Stereo
+      // 1. two connected device, one for L one for R
+      // 2. one connected device for both L and R
+      return true;
+    }
+  } else if (strategy_configuration.getAudioLocation() ==
+             setting::AudioLocation::MONO) {
+    if (strategy_configuration.getConnectedDevice() == 1 &&
+        strategy_configuration.getChannelCount() == 1) {
+      // Mono
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
new file mode 100644
index 0000000..402235f
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
@@ -0,0 +1,87 @@
+/*
+ * 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/bluetooth/audio/LeAudioCodecCapabilitiesSetting.h>
+#include <android-base/logging.h>
+
+#include <unordered_map>
+
+#include "aidl_android_hardware_bluetooth_audio_setting.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothLeAudioCodecsProvider {
+ public:
+  static std::vector<LeAudioCodecCapabilitiesSetting>
+  GetLeAudioCodecCapabilities();
+
+ private:
+  static inline std::unordered_map<std::string, setting::Configuration>
+      configuration_map_;
+  static inline std::unordered_map<std::string, setting::CodecConfiguration>
+      codec_configuration_map_;
+  static inline std::unordered_map<std::string, setting::StrategyConfiguration>
+      strategy_configuration_map_;
+
+  static std::vector<setting::Scenario> GetScenarios(
+      const std::optional<setting::LeAudioOffloadSetting>&
+          le_audio_offload_setting);
+  static void UpdateConfigurationsToMap(
+      const std::optional<setting::LeAudioOffloadSetting>&
+          le_audio_offload_setting);
+  static void UpdateCodecConfigurationsToMap(
+      const std::optional<setting::LeAudioOffloadSetting>&
+          le_audio_offload_setting);
+  static void UpdateStrategyConfigurationsToMap(
+      const std::optional<setting::LeAudioOffloadSetting>&
+          le_audio_offload_setting);
+
+  static std::vector<LeAudioCodecCapabilitiesSetting>
+  ComposeLeAudioCodecCapabilities(
+      const std::vector<setting::Scenario>& supported_scenarios);
+
+  static UnicastCapability GetUnicastCapability(
+      const std::string& coding_direction);
+  template <class T>
+  static inline UnicastCapability ComposeUnicastCapability(
+      const CodecType& codec_type, const AudioLocation& audio_location,
+      const uint8_t& device_cnt, const uint8_t& channel_count,
+      const T& capability);
+
+  static inline Lc3Capabilities ComposeLc3Capability(
+      const setting::CodecConfiguration& codec_configuration);
+
+  static inline AudioLocation GetAudioLocation(
+      const setting::AudioLocation& audio_location);
+  static inline CodecType GetCodecType(const setting::CodecType& codec_type);
+
+  static inline bool IsValidCodecConfiguration(
+      const setting::CodecConfiguration& codec_configuration);
+  static inline bool IsValidStrategyConfiguration(
+      const setting::StrategyConfiguration& strategy_configuration);
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml
new file mode 100644
index 0000000..c7904b3
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!---
+  This is an example to configure LE Audio hardware offload supported capability settings
+  In the follow list, there would be only one list in this file. Add element into each list as needed.
+
+  codecConfigurationList:
+    Supported codec capability along with its parameter setting
+
+  strategyConfigurationList:
+     ASE Configuration strategies
+
+  configurationList:
+    For each configuration , there are two attributes
+      - codecConfiguration
+      - strategyConfiguration
+
+  scenarioList:
+    There would be only one `scenarios` group
+    For each scenario, the are two attributes
+      - encode
+      - decode
+    If a scenario is unidirectional, mark another direction as `invalid`
+    The configuration should be chosen from `configurationList`
+-->
+<leAudioOffloadSetting>
+  <scenarioList>
+    <!-- encode only -->
+    <scenario encode="OneChanMono_16_1" decode="invalid"/>
+    <scenario encode="TwoChanStereo_16_1" decode="invalid"/>
+    <scenario encode="OneChanStereo_16_1" decode="invalid"/>
+    <scenario encode="OneChanMono_16_2" decode="invalid"/>
+    <scenario encode="TwoChanStereo_16_2" decode="invalid"/>
+    <scenario encode="OneChanStereo_16_2" decode="invalid"/>
+    <!-- encode and decode -->
+    <scenario encode="OneChanStereo_16_1" decode="OneChanStereo_16_1"/>
+    <scenario encode="OneChanStereo_16_1" decode="OneChanMono_16_1"/>
+    <scenario encode="TwoChanStereo_16_1" decode="OneChanMono_16_1"/>
+    <scenario encode="OneChanMono_16_1" decode="OneChanMono_16_1"/>
+    <scenario encode="OneChanStereo_16_2" decode="OneChanStereo_16_2"/>
+    <scenario encode="OneChanStereo_16_2" decode="OneChanMono_16_2"/>
+    <scenario encode="TwoChanStereo_16_2" decode="OneChanMono_16_2"/>
+    <scenario encode="OneChanMono_16_2" decode="OneChanMono_16_2"/>
+  </scenarioList>
+  <configurationList>
+    <configuration name="OneChanMono_16_1" codecConfiguration="LC3_16k_1" strategyConfiguration="MONO_ONE_CIS_PER_DEVICE"/>
+    <configuration name="TwoChanStereo_16_1" codecConfiguration="LC3_16k_1" strategyConfiguration="STEREO_TWO_CISES_PER_DEVICE"/>
+    <configuration name="OneChanStereo_16_1" codecConfiguration="LC3_16k_1" strategyConfiguration="STEREO_ONE_CIS_PER_DEVICE"/>
+    <configuration name="OneChanMono_16_2" codecConfiguration="LC3_16k_2" strategyConfiguration="MONO_ONE_CIS_PER_DEVICE"/>
+    <configuration name="TwoChanStereo_16_2" codecConfiguration="LC3_16k_2" strategyConfiguration="STEREO_TWO_CISES_PER_DEVICE"/>
+    <configuration name="OneChanStereo_16_2" codecConfiguration="LC3_16k_2" strategyConfiguration="STEREO_ONE_CIS_PER_DEVICE"/>
+  </configurationList>
+  <codecConfigurationList>
+    <codecConfiguration name="LC3_16k_1" codec="LC3" samplingFrequency="16000" frameDurationUs="7500" octetsPerCodecFrame="30"/>
+    <codecConfiguration name="LC3_16k_2" codec="LC3" samplingFrequency="16000" frameDurationUs="10000" octetsPerCodecFrame="40"/>
+  </codecConfigurationList>
+  <strategyConfigurationList>
+    <strategyConfiguration name="STEREO_ONE_CIS_PER_DEVICE" audioLocation="STEREO" connectedDevice="2" channelCount="1"/>
+    <strategyConfiguration name="STEREO_TWO_CISES_PER_DEVICE" audioLocation="STEREO" connectedDevice="1" channelCount="2"/>
+    <strategyConfiguration name="MONO_ONE_CIS_PER_DEVICE" audioLocation="MONO" connectedDevice="1" channelCount="1"/>
+  </strategyConfigurationList>
+</leAudioOffloadSetting>
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd
new file mode 100644
index 0000000..213e597
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd
@@ -0,0 +1,74 @@
+<!-- LE Audio Offload Codec Capability Schema -->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+  <xs:element name="leAudioOffloadSetting">
+    <xs:complexType>
+      <xs:element ref="scenarioList" minOccurs="1" maxOccurs="1"/>
+      <xs:element ref="configurationList" minOccurs="1" maxOccurs="1"/>
+      <xs:element ref="codecConfigurationList" minOccurs="1" maxOccurs="1"/>
+      <xs:element ref="strategyConfigurationList" minOccurs="1" maxOccurs="1"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="scenarioList">
+    <xs:complexType>
+      <xs:element ref="scenario" minOccurs="1" maxOccurs="unbounded"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="configurationList">
+    <xs:complexType>
+      <xs:element ref="configuration" minOccurs="1" maxOccurs="unbounded"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="codecConfigurationList">
+    <xs:complexType>
+      <xs:element ref="codecConfiguration" minOccurs="1" maxOccurs="unbounded"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="strategyConfigurationList">
+    <xs:complexType>
+      <xs:element ref="strategyConfiguration" minOccurs="1" maxOccurs="unbounded"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="scenario">
+    <xs:complexType>
+      <xs:attribute name="encode" type="xs:string"/>
+      <xs:attribute name="decode" type="xs:string"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="configuration">
+    <xs:complexType>
+      <xs:attribute name="name" type="xs:string"/>
+      <xs:attribute name="codecConfiguration" type="xs:string"/>
+      <xs:attribute name="strategyConfiguration" type="xs:string"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="codecConfiguration">
+    <xs:complexType>
+      <xs:attribute name="name" type="xs:string"/>
+      <xs:attribute name="codec" type="codecType"/>
+      <xs:attribute name="pcmBitDepth" type="xs:unsignedByte"/>
+      <xs:attribute name="samplingFrequency" type="xs:int"/>
+      <xs:attribute name="frameDurationUs" type="xs:int"/>
+      <xs:attribute name="octetsPerCodecFrame" type="xs:int"/>
+      <xs:attribute name="codecFrameBlocksPerSdu" type="xs:unsignedByte"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="strategyConfiguration">
+    <xs:complexType>
+      <xs:attribute name="name" type="xs:string"/>
+      <xs:attribute name="audioLocation" type="audioLocation"/>
+      <xs:attribute name="connectedDevice" type="xs:unsignedByte"/>
+      <xs:attribute name="channelCount" type="xs:unsignedByte"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:simpleType name="audioLocation">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="MONO"/>
+      <xs:enumeration value="STEREO"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="codecType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="LC3"/>
+    </xs:restriction>
+  </xs:simpleType>
+</xs:schema>
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt
new file mode 100644
index 0000000..06aa21a
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt
@@ -0,0 +1,111 @@
+// Signature format: 2.0
+package aidl.android.hardware.bluetooth.audio.setting {
+
+  public enum AudioLocation {
+    method public String getRawName();
+    enum_constant public static final aidl.android.hardware.bluetooth.audio.setting.AudioLocation MONO;
+    enum_constant public static final aidl.android.hardware.bluetooth.audio.setting.AudioLocation STEREO;
+  }
+
+  public class CodecConfiguration {
+    ctor public CodecConfiguration();
+    method public aidl.android.hardware.bluetooth.audio.setting.CodecType getCodec();
+    method public short getCodecFrameBlocksPerSdu();
+    method public int getFrameDurationUs();
+    method public String getName();
+    method public int getOctetsPerCodecFrame();
+    method public short getPcmBitDepth();
+    method public int getSamplingFrequency();
+    method public void setCodec(aidl.android.hardware.bluetooth.audio.setting.CodecType);
+    method public void setCodecFrameBlocksPerSdu(short);
+    method public void setFrameDurationUs(int);
+    method public void setName(String);
+    method public void setOctetsPerCodecFrame(int);
+    method public void setPcmBitDepth(short);
+    method public void setSamplingFrequency(int);
+  }
+
+  public class CodecConfigurationList {
+    ctor public CodecConfigurationList();
+    method public java.util.List<aidl.android.hardware.bluetooth.audio.setting.CodecConfiguration> getCodecConfiguration();
+  }
+
+  public enum CodecType {
+    method public String getRawName();
+    enum_constant public static final aidl.android.hardware.bluetooth.audio.setting.CodecType LC3;
+  }
+
+  public class Configuration {
+    ctor public Configuration();
+    method public String getCodecConfiguration();
+    method public String getName();
+    method public String getStrategyConfiguration();
+    method public void setCodecConfiguration(String);
+    method public void setName(String);
+    method public void setStrategyConfiguration(String);
+  }
+
+  public class ConfigurationList {
+    ctor public ConfigurationList();
+    method public java.util.List<aidl.android.hardware.bluetooth.audio.setting.Configuration> getConfiguration();
+  }
+
+  public class LeAudioOffloadSetting {
+    ctor public LeAudioOffloadSetting();
+    method public aidl.android.hardware.bluetooth.audio.setting.CodecConfigurationList getCodecConfigurationList();
+    method public aidl.android.hardware.bluetooth.audio.setting.ConfigurationList getConfigurationList();
+    method public aidl.android.hardware.bluetooth.audio.setting.ScenarioList getScenarioList();
+    method public aidl.android.hardware.bluetooth.audio.setting.StrategyConfigurationList getStrategyConfigurationList();
+    method public void setCodecConfigurationList(aidl.android.hardware.bluetooth.audio.setting.CodecConfigurationList);
+    method public void setConfigurationList(aidl.android.hardware.bluetooth.audio.setting.ConfigurationList);
+    method public void setScenarioList(aidl.android.hardware.bluetooth.audio.setting.ScenarioList);
+    method public void setStrategyConfigurationList(aidl.android.hardware.bluetooth.audio.setting.StrategyConfigurationList);
+  }
+
+  public class Scenario {
+    ctor public Scenario();
+    method public String getDecode();
+    method public String getEncode();
+    method public void setDecode(String);
+    method public void setEncode(String);
+  }
+
+  public class ScenarioList {
+    ctor public ScenarioList();
+    method public java.util.List<aidl.android.hardware.bluetooth.audio.setting.Scenario> getScenario();
+  }
+
+  public class StrategyConfiguration {
+    ctor public StrategyConfiguration();
+    method public aidl.android.hardware.bluetooth.audio.setting.AudioLocation getAudioLocation();
+    method public short getChannelCount();
+    method public short getConnectedDevice();
+    method public String getName();
+    method public void setAudioLocation(aidl.android.hardware.bluetooth.audio.setting.AudioLocation);
+    method public void setChannelCount(short);
+    method public void setConnectedDevice(short);
+    method public void setName(String);
+  }
+
+  public class StrategyConfigurationList {
+    ctor public StrategyConfigurationList();
+    method public java.util.List<aidl.android.hardware.bluetooth.audio.setting.StrategyConfiguration> getStrategyConfiguration();
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method public static aidl.android.hardware.bluetooth.audio.setting.CodecConfiguration readCodecConfiguration(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static aidl.android.hardware.bluetooth.audio.setting.CodecConfigurationList readCodecConfigurationList(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static aidl.android.hardware.bluetooth.audio.setting.Configuration readConfiguration(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static aidl.android.hardware.bluetooth.audio.setting.ConfigurationList readConfigurationList(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static aidl.android.hardware.bluetooth.audio.setting.LeAudioOffloadSetting readLeAudioOffloadSetting(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static aidl.android.hardware.bluetooth.audio.setting.Scenario readScenario(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static aidl.android.hardware.bluetooth.audio.setting.ScenarioList readScenarioList(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static aidl.android.hardware.bluetooth.audio.setting.StrategyConfiguration readStrategyConfiguration(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static aidl.android.hardware.bluetooth.audio.setting.StrategyConfigurationList readStrategyConfigurationList(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_current.txt b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_current.txt
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_removed.txt b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/last_removed.txt
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/removed.txt b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 6866776..b0ae20e 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -7883,6 +7883,7 @@
             }
         }
 
+        camera_metadata_t* staticMetadata;
         camera_metadata_ro_entry physicalMultiResStreamConfigs;
         camera_metadata_ro_entry physicalStreamConfigs;
         camera_metadata_ro_entry physicalMaxResolutionStreamConfigs;
@@ -7901,8 +7902,9 @@
 
             ret = subDevice->getCameraCharacteristics([&](auto status, const auto& chars) {
                 ASSERT_EQ(Status::OK, status);
-                const camera_metadata_t* staticMetadata =
-                        reinterpret_cast<const camera_metadata_t*>(chars.data());
+                staticMetadata = clone_camera_metadata(
+                        reinterpret_cast<const camera_metadata_t*>(chars.data()));
+                ASSERT_NE(nullptr, staticMetadata);
                 rc = getSystemCameraKind(staticMetadata, &physSystemCameraKind);
                 ASSERT_EQ(rc, Status::OK);
                 // Make sure that the system camera kind of a non-hidden
@@ -7936,7 +7938,9 @@
                         verifyCameraCharacteristics(status, chars);
                         verifyMonochromeCharacteristics(chars, deviceVersion);
 
-                        auto staticMetadata = (const camera_metadata_t*)chars.data();
+                        staticMetadata = clone_camera_metadata(
+                                reinterpret_cast<const camera_metadata_t*>(chars.data()));
+                        ASSERT_NE(nullptr, staticMetadata);
                         retcode = find_camera_metadata_ro_entry(
                                 staticMetadata, ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
                         bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2);
@@ -8064,6 +8068,7 @@
                 }
             }
         }
+        free_camera_metadata(staticMetadata);
     }
 
     // If a multi-resolution stream is supported, there must be at least one
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index 20f32bf..2c2f1b2 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -1181,6 +1181,7 @@
         camera_metadata_ro_entry physicalMultiResStreamConfigs;
         camera_metadata_ro_entry physicalStreamConfigs;
         camera_metadata_ro_entry physicalMaxResolutionStreamConfigs;
+        CameraMetadata physChars;
         bool isUltraHighRes = false;
         std::unordered_set<int32_t> subCameraPrivacyTestPatterns;
         if (isPublicId) {
@@ -1189,12 +1190,11 @@
             ASSERT_TRUE(ret.isOk());
             ASSERT_NE(subDevice, nullptr);
 
-            CameraMetadata subDeviceChars;
-            ret = subDevice->getCameraCharacteristics(&subDeviceChars);
+            ret = subDevice->getCameraCharacteristics(&physChars);
             ASSERT_TRUE(ret.isOk());
 
             const camera_metadata_t* staticMetadata =
-                    reinterpret_cast<const camera_metadata_t*>(subDeviceChars.metadata.data());
+                    reinterpret_cast<const camera_metadata_t*>(physChars.metadata.data());
             retStatus = getSystemCameraKind(staticMetadata, &physSystemCameraKind);
             ASSERT_EQ(retStatus, Status::OK);
 
@@ -1215,7 +1215,6 @@
             getPrivacyTestPatternModes(staticMetadata, &subCameraPrivacyTestPatterns);
         } else {
             // Check camera characteristics for hidden camera id
-            CameraMetadata physChars;
             ndk::ScopedAStatus ret =
                     device->getPhysicalCameraCharacteristics(physicalId, &physChars);
             ASSERT_TRUE(ret.isOk());
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 4e2a4ed..20ba9a9 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -16,7 +16,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
+    <hal format="hidl" optional="true">
         <name>android.hardware.audio.effect</name>
         <version>6.0</version>
         <version>7.0</version>
@@ -37,7 +37,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="false">
+    <hal format="aidl" optional="true">
         <name>android.hardware.audio.effect</name>
         <version>1</version>
         <interface>
@@ -208,6 +208,14 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.confirmationui</name>
+        <version>1</version>
+        <interface>
+            <name>IConfirmationUI</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.contexthub</name>
         <interface>
             <name>IContextHub</name>
@@ -241,7 +249,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="false">
+    <hal format="hidl" optional="true">
         <name>android.hardware.gatekeeper</name>
         <version>1.0</version>
         <interface>
@@ -250,6 +258,14 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.gatekeeper</name>
+        <version>1</version>
+        <interface>
+            <name>IGatekeeper</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.gnss</name>
         <version>2</version>
         <interface>
diff --git a/confirmationui/OWNERS b/confirmationui/OWNERS
new file mode 100644
index 0000000..2bcdb0e
--- /dev/null
+++ b/confirmationui/OWNERS
@@ -0,0 +1,2 @@
+swillden@google.com
+subrahmanyaman@google.com
diff --git a/confirmationui/aidl/Android.bp b/confirmationui/aidl/Android.bp
new file mode 100644
index 0000000..4ba4acd
--- /dev/null
+++ b/confirmationui/aidl/Android.bp
@@ -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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+    name: "android.hardware.confirmationui",
+    vendor_available: true,
+    imports: [
+        "android.hardware.security.keymint-V2",
+    ],
+    srcs: ["android/hardware/confirmationui/*.aidl"],
+    stability: "vintf",
+    backend: {
+        java: {
+            platform_apis: true,
+        },
+        ndk: {
+            apps_enabled: false,
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+}
diff --git a/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationResultCallback.aidl b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationResultCallback.aidl
new file mode 100644
index 0000000..6d6ec97
--- /dev/null
+++ b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationResultCallback.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.confirmationui;
+@VintfStability
+interface IConfirmationResultCallback {
+  void result(in int error, in byte[] formattedMessage, in byte[] confirmationToken);
+}
diff --git a/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationUI.aidl b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationUI.aidl
new file mode 100644
index 0000000..c5c7aa7
--- /dev/null
+++ b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/IConfirmationUI.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.confirmationui;
+@VintfStability
+interface IConfirmationUI {
+  void abort();
+  void deliverSecureInputEvent(in android.hardware.security.keymint.HardwareAuthToken secureInputToken);
+  void promptUserConfirmation(in android.hardware.confirmationui.IConfirmationResultCallback resultCB, in byte[] promptText, in byte[] extraData, in @utf8InCpp String locale, in android.hardware.confirmationui.UIOption[] uiOptions);
+  const int OK = 0;
+  const int CANCELED = 1;
+  const int ABORTED = 2;
+  const int OPERATION_PENDING = 3;
+  const int IGNORED = 4;
+  const int SYSTEM_ERROR = 5;
+  const int UNIMPLEMENTED = 6;
+  const int UNEXPECTED = 7;
+  const int UI_ERROR = 65536;
+  const int UI_ERROR_MISSING_GLYPH = 65537;
+  const int UI_ERROR_MESSAGE_TOO_LONG = 65538;
+  const int UI_ERROR_MALFORMED_UTF8ENCODING = 65539;
+  const int TEST_KEY_BYTE = 165;
+  const int MAX_MESSAGE_SIZE = 6144;
+}
diff --git a/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/TestModeCommands.aidl b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/TestModeCommands.aidl
new file mode 100644
index 0000000..b8629d1
--- /dev/null
+++ b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/TestModeCommands.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.confirmationui;
+@Backing(type="int") @VintfStability
+enum TestModeCommands {
+  OK_EVENT = 0,
+  CANCEL_EVENT = 1,
+}
diff --git a/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/UIOption.aidl b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/UIOption.aidl
new file mode 100644
index 0000000..ebecf9e
--- /dev/null
+++ b/confirmationui/aidl/aidl_api/android.hardware.confirmationui/current/android/hardware/confirmationui/UIOption.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.confirmationui;
+@Backing(type="int") @VintfStability
+enum UIOption {
+  ACCESSIBILITY_INVERTED = 0,
+  ACCESSIBILITY_MAGNIFIED = 1,
+}
diff --git a/confirmationui/aidl/android/hardware/confirmationui/IConfirmationResultCallback.aidl b/confirmationui/aidl/android/hardware/confirmationui/IConfirmationResultCallback.aidl
new file mode 100644
index 0000000..2165fdd
--- /dev/null
+++ b/confirmationui/aidl/android/hardware/confirmationui/IConfirmationResultCallback.aidl
@@ -0,0 +1,66 @@
+/*
+ * 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.confirmationui;
+
+import android.hardware.confirmationui.IConfirmationUI;
+
+/**
+ * Callback interface passed to IConfirmationUI::promptUserConfirmation().
+ * Informs the caller about the result of the prompt operation.
+ */
+@VintfStability
+interface IConfirmationResultCallback {
+    /**
+     * This callback is called by the confirmation provider when it stops prompting the user.
+     * Iff the user has confirmed the prompted text, error is ErrorCode::OK and the
+     * parameters formattedMessage and confirmationToken hold the values needed to request
+     * a signature from keymaster.
+     * In all other cases formattedMessage and confirmationToken must be of length 0.
+     *
+     * @param error - OK: IFF the user has confirmed the prompt.
+     *              - CANCELED: If the user has pressed the cancel button.
+     *              - ABORTED: If IConfirmationUI::abort() was called.
+     *              - SYSTEM_ERROR: If an unexpected System error occurred that prevented the TUI
+     *                             from being shut down gracefully.
+     *
+     * @param formattedMessage holds the prompt text and extra data.
+     *                         The message is CBOR (RFC 7049) encoded and has the following format:
+     *                         CBOR_MAP{ "prompt", <promptText>, "extra", <extraData> }
+     *                         The message is a CBOR encoded map (type 5) with the keys
+     *                         "prompt" and "extra". The keys are encoded as CBOR text string
+     *                         (type 3). The value <promptText> is encoded as CBOR text string
+     *                         (type 3), and the value <extraData> is encoded as CBOR byte string
+     *                         (type 2). The map must have exactly one key value pair for each of
+     *                         the keys "prompt" and "extra". Other keys are not allowed.
+     *                         The value of "prompt" is given by the proptText argument to
+     *                         IConfirmationUI::promptUserConfirmation and must not be modified
+     *                         by the implementation.
+     *                         The value of "extra" is given by the extraData argument to
+     *                         IConfirmationUI::promptUserConfirmation and must not be modified
+     *                         or interpreted by the implementation.
+     *
+     * @param confirmationToken a 32-byte HMAC-SHA256 value, computed over
+     *                          "confirmation token" || <formattedMessage>
+     *                          i.e. the literal UTF-8 encoded string "confirmation token", without
+     *                          the "", concatenated with the formatted message as returned in the
+     *                          formattedMessage argument. The HMAC is keyed with a 256-bit secret
+     *                          which is shared with Keymaster. In test mode the test key MUST be
+     *                          used (see types.hal TestModeCommands and
+     * IConfirmationUI::TEST_KEY_BYTE).
+     */
+    void result(in int error, in byte[] formattedMessage, in byte[] confirmationToken);
+}
diff --git a/confirmationui/aidl/android/hardware/confirmationui/IConfirmationUI.aidl b/confirmationui/aidl/android/hardware/confirmationui/IConfirmationUI.aidl
new file mode 100644
index 0000000..f071126
--- /dev/null
+++ b/confirmationui/aidl/android/hardware/confirmationui/IConfirmationUI.aidl
@@ -0,0 +1,146 @@
+/*
+ * 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.confirmationui;
+
+import android.hardware.confirmationui.IConfirmationResultCallback;
+import android.hardware.confirmationui.UIOption;
+import android.hardware.security.keymint.HardwareAuthToken;
+
+@VintfStability
+interface IConfirmationUI {
+    // Possible Errors.
+    /**
+     * API call succeeded or the user gave approval (result callback).
+     */
+    const int OK = 0;
+    /**
+     * The user canceled the TUI (result callback).
+     */
+    const int CANCELED = 1;
+    /**
+     * IConfirmationUI::abort() was called. (result callback).
+     */
+    const int ABORTED = 2;
+    /**
+     * Cannot start another prompt.
+     */
+    const int OPERATION_PENDING = 3;
+    /**
+     * IConfirmationUI::deliverSecureInputEvent call was ignored.
+     */
+    const int IGNORED = 4;
+    /**
+     * An unexpected system error occurred.
+     */
+    const int SYSTEM_ERROR = 5;
+    /**
+     * Returned by an unimplemented API call.
+     */
+    const int UNIMPLEMENTED = 6;
+    /**
+     * This is returned when an error is diagnosed that should have been
+     * caught by earlier input sanitization. Should never be seen in production.
+     */
+    const int UNEXPECTED = 7;
+    /**
+     * General UI error.
+     */
+    const int UI_ERROR = 0x10000;
+    /**
+     * This is returned if there is no corresponding glyph for a character.
+     */
+    const int UI_ERROR_MISSING_GLYPH = 0x10001;
+    /**
+     * The implementation must return this error code on promptUserConfirmation if the
+     * resulting formatted message does not fit into MAX_MESSAGE_SIZE bytes. It is
+     * advised that the implementation formats the message upon receiving this API call to
+     * be able to diagnose this syndrome.
+     */
+    const int UI_ERROR_MESSAGE_TOO_LONG = 0x10002;
+    /**
+     * This is returned if the UTF8 encoding is malformed.
+     */
+    const int UI_ERROR_MALFORMED_UTF8ENCODING = 0x10003;
+
+    // Constants
+    /**
+     * The test key is 32byte word with all bytes set to TEST_KEY_BYTE.
+     */
+    const int TEST_KEY_BYTE = 0xA5;
+    /**
+     * This defines the maximum message size. This indirectly limits the size of the prompt text
+     * and the extra data that can be passed to the confirmation UI. The prompt text and extra data
+     * must fit in to this size including CBOR header information.
+     */
+    const int MAX_MESSAGE_SIZE = 0x1800;
+
+    /**
+     * Aborts a pending user prompt. This allows the framework to gracefully end a TUI dialog.
+     * If a TUI operation was pending the corresponding call back is informed with
+     * ErrorCode::Aborted.
+     */
+    void abort();
+
+    /**
+     * DeliverSecureInput is used by the framework to deliver a secure input event to the
+     * confirmation provider.
+     *
+     * VTS test mode:
+     * This function can be used to test certain code paths non-interactively.
+     * See TestModeCommands.aidl for details.
+     *
+     * @param secureInputToken An authentication token as generated by Android authentication
+     *                         providers.
+     */
+    void deliverSecureInputEvent(in HardwareAuthToken secureInputToken);
+
+    /**
+     * Asynchronously initiates a confirmation UI dialog prompting the user to confirm a given text.
+     * The TUI prompt must be implemented in such a way that a positive response indicates with
+     * high confidence that a user has seen the given prompt text even if the Android framework
+     * including the kernel was compromised.
+     *
+     * Service status return:
+     *
+     * OK IFF the dialog was successfully started. In this case, and only in this
+     *                      case, the implementation must, eventually, call the callback to
+     *                      indicate completion.
+     * OPERATION_PENDING is returned when the confirmation provider is currently
+     *                      in use.
+     * SYSTEM_ERROR an error occurred trying to communicate with the confirmation
+     *                      provider (e.g. trusted app).
+     * UI_ERROR the confirmation provider encountered an issue with displaying
+     *                      the prompt text to the user.
+     *
+     * @param resultCB Implementation of IResultCallback. Used by the implementation to report
+     *                 the result of the current pending user prompt.
+     *
+     * @param promptText UTF-8 encoded bytes which is to be presented to the user.
+     *
+     * @param extraData A binary blob that must be included in the formatted output message as is.
+     *                  It is opaque to the implementation. Implementations must neither interpret
+     *                  nor modify the content.
+     *
+     * @param locale String specifying the locale that must be used by the TUI dialog. The string
+     *                      is an IETF BCP 47 tag.
+     *
+     * @param uiOptions A set of uiOptions manipulating how the confirmation prompt is displayed.
+     *                  Refer to UIOption in types.hal for possible options.
+     */
+    void promptUserConfirmation(in IConfirmationResultCallback resultCB, in byte[] promptText,
+            in byte[] extraData, in @utf8InCpp String locale, in UIOption[] uiOptions);
+}
diff --git a/confirmationui/aidl/android/hardware/confirmationui/TestModeCommands.aidl b/confirmationui/aidl/android/hardware/confirmationui/TestModeCommands.aidl
new file mode 100644
index 0000000..5b1d8fb
--- /dev/null
+++ b/confirmationui/aidl/android/hardware/confirmationui/TestModeCommands.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.confirmationui;
+
+/**
+ * Test mode commands.
+ *
+ * IConfirmationUI::deliverSecureInputEvent can be used to test certain code paths.
+ * To that end, the caller passes an auth token that has an HMAC keyed with the test key
+ * (see IConfirmationUI::TEST_KEY_BYTE). Implementations first check the HMAC against test key.
+ * If the test key produces a matching HMAC, the implementation evaluates the challenge field
+ * of the auth token against the values defined in TestModeCommand.
+ * If the command indicates that a confirmation token is to be generated the test key MUST be used
+ * to generate this confirmation token.
+ *
+ * See command code for individual test command descriptions.
+ */
+@VintfStability
+@Backing(type="int")
+enum TestModeCommands {
+    /**
+     * Simulates the user pressing the OK button on the UI. If no operation is pending
+     * ResponseCode::Ignored must be returned. A pending operation is finalized successfully
+     * see IConfirmationResultCallback::result, however, the test key
+     * (see IConfirmationUI::TEST_KEY_BYTE) MUST be used to generate the confirmation token.
+     */
+    OK_EVENT = 0,
+    /**
+     * Simulates the user pressing the CANCEL button on the UI. If no operation is pending
+     * Result::Ignored must be returned. A pending operation is finalized as specified in
+     * IConfirmationResultCallback.hal.
+     */
+    CANCEL_EVENT = 1,
+}
diff --git a/confirmationui/aidl/android/hardware/confirmationui/UIOption.aidl b/confirmationui/aidl/android/hardware/confirmationui/UIOption.aidl
new file mode 100644
index 0000000..b242c53
--- /dev/null
+++ b/confirmationui/aidl/android/hardware/confirmationui/UIOption.aidl
@@ -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.
+ */
+
+package android.hardware.confirmationui;
+
+/**
+ * UI modification options.
+ */
+@VintfStability
+@Backing(type="int")
+enum UIOption {
+    /**
+     * Accessibility: Requests color inverted style.
+     */
+    ACCESSIBILITY_INVERTED = 0,
+    /**
+     * Accessibility: Requests magnified style.
+     */
+    ACCESSIBILITY_MAGNIFIED = 1,
+}
diff --git a/confirmationui/aidl/vts/functional/Android.bp b/confirmationui/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..3649c87
--- /dev/null
+++ b/confirmationui/aidl/vts/functional/Android.bp
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalConfirmationUITargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "keymint_use_latest_hal_aidl_ndk_shared",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "VtsHalConfirmationUITargetTest.cpp",
+    ],
+    static_libs: [
+        "android.hardware.confirmationui-V1-ndk",
+        "libcn-cbor",
+        "android.hardware.confirmationui-support-lib",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcrypto",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/confirmationui/aidl/vts/functional/VtsHalConfirmationUITargetTest.cpp b/confirmationui/aidl/vts/functional/VtsHalConfirmationUITargetTest.cpp
new file mode 100644
index 0000000..61dae8b
--- /dev/null
+++ b/confirmationui/aidl/vts/functional/VtsHalConfirmationUITargetTest.cpp
@@ -0,0 +1,535 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ConfirmationIOAidlHalTest"
+
+#include <algorithm>
+#include <condition_variable>
+#include <future>
+#include <iostream>
+#include <memory>
+#include <mutex>
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/confirmationui/BnConfirmationResultCallback.h>
+#include <aidl/android/hardware/confirmationui/IConfirmationUI.h>
+#include <aidl/android/hardware/confirmationui/TestModeCommands.h>
+#include <aidl/android/hardware/confirmationui/UIOption.h>
+#include <android-base/thread_annotations.h>
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+#include <cutils/log.h>
+
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+
+#include <cn-cbor/cn-cbor.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/binder_status.h>
+
+static constexpr int TIMEOUT_PERIOD = 10;
+
+namespace aidl::android::hardware::confirmationui::test {
+using ::aidl::android::hardware::security::keymint::HardwareAuthenticatorType;
+using ::aidl::android::hardware::security::keymint::HardwareAuthToken;
+using ::android::hardware::confirmationui::support::auth_token_key_t;
+using ::android::hardware::confirmationui::support::ByteBufferProxy;
+using ::android::hardware::confirmationui::support::HMac;
+using ::android::hardware::confirmationui::support::hmac_t;
+using ::android::hardware::confirmationui::support::hton;
+using ::android::hardware::confirmationui::support::NullOr;
+using std::shared_ptr;
+using std::string;
+using std::vector;
+
+namespace {
+const auth_token_key_t testKey(static_cast<uint8_t>(IConfirmationUI::TEST_KEY_BYTE));
+
+class HMacImplementation {
+  public:
+    static NullOr<hmac_t> hmac256(const auth_token_key_t& key,
+                                  std::initializer_list<ByteBufferProxy> buffers) {
+        HMAC_CTX hmacCtx;
+        HMAC_CTX_init(&hmacCtx);
+        if (!HMAC_Init_ex(&hmacCtx, key.data(), key.size(), EVP_sha256(), nullptr)) {
+            return {};
+        }
+        for (auto& buffer : buffers) {
+            if (!HMAC_Update(&hmacCtx, buffer.data(), buffer.size())) {
+                return {};
+            }
+        }
+        hmac_t result;
+        if (!HMAC_Final(&hmacCtx, result.data(), nullptr)) {
+            return {};
+        }
+        return result;
+    }
+};
+
+using HMacer = HMac<HMacImplementation>;
+
+template <typename... Data>
+vector<uint8_t> testHMAC(const Data&... data) {
+    auto hmac = HMacer::hmac256(testKey, data...);
+    if (!hmac.isOk()) {
+        ADD_FAILURE() << "Failed to compute test hmac.  This is a self-test error.";
+        return {};
+    }
+    vector<uint8_t> result(hmac.value().size());
+    std::copy(hmac.value().data(), hmac.value().data() + hmac.value().size(), result.data());
+    return result;
+}
+
+template <typename T>
+auto toBytes(const T& v) -> const uint8_t (&)[sizeof(T)] {
+    return *reinterpret_cast<const uint8_t(*)[sizeof(T)]>(&v);
+}
+
+HardwareAuthToken makeTestToken(const TestModeCommands command, uint64_t timestamp = 0) {
+    HardwareAuthToken auth_token;
+    auth_token.challenge = static_cast<uint64_t>(command);
+    auth_token.userId = 0;
+    auth_token.authenticatorId = 0;
+    auth_token.authenticatorType = HardwareAuthenticatorType::NONE;
+    auth_token.timestamp = {static_cast<int64_t>(timestamp)};
+
+    // Canonical form  of auth-token v0
+    // version (1 byte)
+    // challenge (8 bytes)
+    // user_id (8 bytes)
+    // authenticator_id (8 bytes)
+    // authenticator_type (4 bytes)
+    // timestamp (8 bytes)
+    // total 37 bytes
+    auth_token.mac = testHMAC("\0",
+                              toBytes(auth_token.challenge),                //
+                              toBytes(auth_token.userId),                   //
+                              toBytes(auth_token.authenticatorId),          //
+                              toBytes(hton(auth_token.authenticatorType)),  //
+                              toBytes(hton(auth_token.timestamp)));         //
+
+    return auth_token;
+}
+
+#define DEBUG_CONFRIMATIONUI_UTILS_TEST
+
+#ifdef DEBUG_CONFRIMATIONUI_UTILS_TEST
+std::ostream& hexdump(std::ostream& out, const uint8_t* data, size_t size) {
+    for (size_t i = 0; i < size; ++i) {
+        uint8_t byte = data[i];
+        out << std::hex << std::setw(2) << std::setfill('0') << (unsigned)byte;
+        switch (i & 0xf) {
+            case 0xf:
+                out << "\n";
+                break;
+            case 7:
+                out << "  ";
+                break;
+            default:
+                out << " ";
+                break;
+        }
+    }
+    return out;
+}
+#endif
+
+constexpr char hex_value[256] = {0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 1,  2,  3,  4,  5,  6,  7, 8, 9, 0, 0, 0, 0, 0, 0,  // '0'..'9'
+                                 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 'A'..'F'
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 'a'..'f'
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+std::string hex2str(std::string a) {
+    std::string b;
+    size_t num = a.size() / 2;
+    b.resize(num);
+    for (size_t i = 0; i < num; i++) {
+        b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]);
+    }
+    return b;
+}
+
+int getReturnCode(const ::ndk::ScopedAStatus& result) {
+    if (result.isOk()) return IConfirmationUI::OK;
+
+    if (result.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+        return static_cast<int>(result.getServiceSpecificError());
+    }
+    return result.getStatus();
+}
+
+}  // namespace
+
+class ConfirmationUIAidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    void TearDown() override { confirmator_->abort(); }
+    void SetUp() override {
+        std::string name = GetParam();
+        ASSERT_TRUE(AServiceManager_isDeclared(name.c_str())) << name;
+        ndk::SpAIBinder binder(AServiceManager_waitForService(name.c_str()));
+        ASSERT_NE(binder, nullptr);
+        confirmator_ = IConfirmationUI::fromBinder(binder);
+        ASSERT_NE(confirmator_, nullptr);
+    }
+
+    // Used as a mechanism to inform the test about data/event callback
+    inline void notify() {
+        std::unique_lock<std::mutex> lock(mtx_);
+        cv_.notify_one();
+    }
+
+    // Test code calls this function to wait for data/event callback
+    inline std::cv_status wait() {
+        std::unique_lock<std::mutex> lock(mtx_);
+        auto now = std::chrono::system_clock::now();
+        std::cv_status status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+        return status;
+    }
+
+  protected:
+    shared_ptr<IConfirmationUI> confirmator_;
+
+  private:
+    // synchronization objects
+    std::mutex mtx_;
+    std::condition_variable cv_;
+};
+
+class ConfirmationTestCallback
+    : public ::aidl::android::hardware::confirmationui::BnConfirmationResultCallback {
+  public:
+    ConfirmationTestCallback(ConfirmationUIAidlTest& parent) : parent_(parent){};
+    virtual ~ConfirmationTestCallback() = default;
+
+    ::ndk::ScopedAStatus result(int32_t err, const vector<uint8_t>& msg,
+                                const vector<uint8_t>& confToken) override {
+        error_ = err;
+        formattedMessage_ = msg;
+        confirmationToken_ = confToken;
+        parent_.notify();
+        return ndk::ScopedAStatus::ok();
+    }
+
+    bool verifyConfirmationToken() {
+        static constexpr char confirmationPrefix[] = "confirmation token";
+        EXPECT_EQ(32U, confirmationToken_.size());
+        return 32U == confirmationToken_.size() &&
+               !memcmp(confirmationToken_.data(),
+                       testHMAC(confirmationPrefix, formattedMessage_).data(), 32);
+    }
+
+    int error_;
+    vector<uint8_t> formattedMessage_;
+    vector<uint8_t> confirmationToken_;
+
+  private:
+    ConfirmationUIAidlTest& parent_;
+};
+
+struct CnCborDeleter {
+    void operator()(cn_cbor* ptr) { cn_cbor_free(ptr); }
+};
+
+typedef std::unique_ptr<cn_cbor, CnCborDeleter> CnCborPtr;
+
+// Simulates the User taping Ok
+TEST_P(ConfirmationUIAidlTest, UserOkTest) {
+    static constexpr char test_prompt[] = "Me first, gimme gimme!";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk());
+    // Simulate the user taping ok.
+    ASSERT_TRUE(confirmator_->deliverSecureInputEvent(makeTestToken(TestModeCommands::OK_EVENT))
+                        .isOk());
+    // Wait for the callback.
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    ASSERT_EQ(IConfirmationUI::OK, conf_cb->error_);
+
+    ASSERT_TRUE(conf_cb->verifyConfirmationToken());
+
+    cn_cbor_errback cn_cbor_error;
+    auto parsed_message = CnCborPtr(cn_cbor_decode(
+            conf_cb->formattedMessage_.data(), conf_cb->formattedMessage_.size(), &cn_cbor_error));
+    // is parsable CBOR
+    ASSERT_TRUE(parsed_message.get());
+    // is a map
+    ASSERT_EQ(CN_CBOR_MAP, parsed_message->type);
+
+    // the message must have exactly 2 key value pairs.
+    // cn_cbor holds 2*<no_of_pairs> in the length field
+    ASSERT_EQ(4, parsed_message->length);
+    // map has key "prompt"
+    auto prompt = cn_cbor_mapget_string(parsed_message.get(), "prompt");
+    ASSERT_TRUE(prompt);
+    ASSERT_EQ(CN_CBOR_TEXT, prompt->type);
+    ASSERT_EQ(22, prompt->length);
+    ASSERT_EQ(0, memcmp(test_prompt, prompt->v.str, 22));
+    // map has key "extra"
+    auto extra_out = cn_cbor_mapget_string(parsed_message.get(), "extra");
+    ASSERT_TRUE(extra_out);
+    ASSERT_EQ(CN_CBOR_BYTES, extra_out->type);
+    ASSERT_EQ(3, extra_out->length);
+    ASSERT_EQ(0, memcmp(test_extra, extra_out->v.bytes, 3));
+}
+
+// Initiates a confirmation prompt with a message that is too long
+TEST_P(ConfirmationUIAidlTest, MessageTooLongTest) {
+    static constexpr uint8_t test_extra[IConfirmationUI::MAX_MESSAGE_SIZE] = {};
+    static constexpr char test_prompt[] = "D\'oh!";
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + sizeof(test_extra));
+    auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {});
+    ASSERT_EQ(IConfirmationUI::UI_ERROR_MESSAGE_TOO_LONG, getReturnCode(result));
+}
+
+// If the message gets very long some HAL implementations might fail even before the message
+// reaches the trusted app implementation. But the HAL must still diagnose the correct error.
+TEST_P(ConfirmationUIAidlTest, MessageWayTooLongTest) {
+    static constexpr uint8_t test_extra[(IConfirmationUI::MAX_MESSAGE_SIZE)*10] = {};
+    static constexpr char test_prompt[] = "D\'oh!";
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + sizeof(test_extra));
+    auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {});
+    ASSERT_EQ(IConfirmationUI::UI_ERROR_MESSAGE_TOO_LONG, getReturnCode(result));
+}
+
+// Simulates the User tapping the Cancel
+TEST_P(ConfirmationUIAidlTest, UserCancelTest) {
+    static constexpr char test_prompt[] = "Me first, gimme gimme!";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk());
+
+    // Simulate the user taping ok.
+    ASSERT_TRUE(confirmator_->deliverSecureInputEvent(makeTestToken(TestModeCommands::CANCEL_EVENT))
+                        .isOk());
+    // Wait for the callback.
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    ASSERT_EQ(IConfirmationUI::CANCELED, conf_cb->error_);
+
+    ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+    ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Simulates the framework cancelling an ongoing prompt
+TEST_P(ConfirmationUIAidlTest, AbortTest) {
+    static constexpr char test_prompt[] = "Me first, gimme gimme!";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk());
+
+    confirmator_->abort();
+
+    // Wait for the callback.
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_);
+    ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+    ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 100 'W' characters as required by
+// the design guidelines.
+TEST_P(ConfirmationUIAidlTest, PortableMessageTest1) {
+    static constexpr char test_prompt[] =
+            "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
+            "WWWWWWWWWWWWWW";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk());
+
+    confirmator_->abort();
+
+    // Wait for the callback.
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_);
+    ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+    ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 100 'W' characters as required by
+// the design guidelines in magnified mode.
+TEST_P(ConfirmationUIAidlTest, PortableMessageTest1Magnified) {
+    static constexpr char test_prompt[] =
+            "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW"
+            "WWWWWWWWWWWWWW";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_TRUE(confirmator_
+                        ->promptUserConfirmation(conf_cb, prompt_text, extra, "en",
+                                                 {UIOption::ACCESSIBILITY_MAGNIFIED})
+                        .isOk());
+
+    confirmator_->abort();
+
+    // Wait for the callback.
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_);
+    ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+    ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 8 groups of 12 'W' characters as
+// required by the design guidelines.
+TEST_P(ConfirmationUIAidlTest, PortableMessageTest2) {
+    static constexpr char test_prompt[] =
+            "WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW "
+            "WWWWWWWWWWWW WWWWWWWWWWWW";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_TRUE(confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {}).isOk());
+
+    confirmator_->abort();
+
+    // Wait for the callback.
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_);
+    ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+    ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Tests if the confirmation dialog can successfully render 8 groups of 12 'W' characters as
+// required by the design guidelines in magnified mode.
+TEST_P(ConfirmationUIAidlTest, PortableMessageTest2Magnified) {
+    static constexpr char test_prompt[] =
+            "WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW WWWWWWWWWWWW "
+            "WWWWWWWWWWWW WWWWWWWWWWWW";
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    ASSERT_TRUE(confirmator_
+                        ->promptUserConfirmation(conf_cb, prompt_text, extra, "en",
+                                                 {UIOption::ACCESSIBILITY_MAGNIFIED})
+                        .isOk());
+
+    confirmator_->abort();
+
+    // Wait for the callback.
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    ASSERT_EQ(IConfirmationUI::ABORTED, conf_cb->error_);
+    ASSERT_EQ(0U, conf_cb->confirmationToken_.size());
+    ASSERT_EQ(0U, conf_cb->formattedMessage_.size());
+}
+
+// Passing malformed UTF-8 to the confirmation UI
+// This test passes a string that ends in the middle of a multibyte character
+TEST_P(ConfirmationUIAidlTest, MalformedUTF8Test1) {
+    static constexpr char test_prompt[] = {char(0xc0), 0};
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {});
+    ASSERT_EQ(IConfirmationUI::UI_ERROR_MALFORMED_UTF8ENCODING, getReturnCode(result));
+}
+
+// Passing malformed UTF-8 to the confirmation UI
+// This test passes a string with a 5-byte character.
+TEST_P(ConfirmationUIAidlTest, MalformedUTF8Test2) {
+    static constexpr char test_prompt[] = {char(0xf8), char(0x82), char(0x82),
+                                           char(0x82), char(0x82), 0};
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {});
+    ASSERT_EQ(IConfirmationUI::UI_ERROR_MALFORMED_UTF8ENCODING, getReturnCode(result));
+}
+
+// Passing malformed UTF-8 to the confirmation UI
+// This test passes a string with a 2-byte character followed by a stray non UTF-8 character.
+TEST_P(ConfirmationUIAidlTest, MalformedUTF8Test3) {
+    static constexpr char test_prompt[] = {char(0xc0), char(0x82), char(0x83), 0};
+    static constexpr uint8_t test_extra[] = {0x1, 0x2, 0x3};
+    shared_ptr<ConfirmationTestCallback> conf_cb =
+            ::ndk::SharedRefBase::make<ConfirmationTestCallback>(*this);
+    vector<uint8_t> prompt_text(test_prompt, test_prompt + strlen(test_prompt));
+    vector<uint8_t> extra(test_extra, test_extra + 3);
+    auto result = confirmator_->promptUserConfirmation(conf_cb, prompt_text, extra, "en", {});
+    ASSERT_EQ(IConfirmationUI::UI_ERROR_MALFORMED_UTF8ENCODING, getReturnCode(result));
+}
+
+// Test the implementation of HMAC SHA 256 against a golden blob.
+TEST(ConfirmationUITestSelfTest, HMAC256SelfTest) {
+    const char key_str[32] = "keykeykeykeykeykeykeykeykeykeyk";
+    const uint8_t(&key)[32] = *reinterpret_cast<const uint8_t(*)[32]>(key_str);
+    auto expected = hex2str("2377fbcaa7fb3f6c20cfa1d9ebc60e9922cf58c909e25e300f3cb57f7805c886");
+    auto result = HMacer::hmac256(key, "value1", "value2", "value3");
+
+#ifdef DEBUG_CONFRIMATIONUI_UTILS_TEST
+    hexdump(std::cout, reinterpret_cast<const uint8_t*>(expected.data()), 32) << std::endl;
+    hexdump(std::cout, result.value().data(), 32) << std::endl;
+#endif
+
+    ByteBufferProxy expected_bytes(expected);
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(expected, result.value());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ConfirmationUIAidlTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, ConfirmationUIAidlTest,
+        testing::ValuesIn(::android::getAidlHalInstanceNames(IConfirmationUI::descriptor)),
+        ::android::PrintInstanceNameToString);
+
+}  // namespace aidl::android::hardware::confirmationui::test
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/gatekeeper/OWNERS b/gatekeeper/OWNERS
new file mode 100644
index 0000000..d95b856
--- /dev/null
+++ b/gatekeeper/OWNERS
@@ -0,0 +1,2 @@
+swillden@google.com
+guangzhu@google.com
diff --git a/gatekeeper/aidl/Android.bp b/gatekeeper/aidl/Android.bp
new file mode 100644
index 0000000..6b1bc7e
--- /dev/null
+++ b/gatekeeper/aidl/Android.bp
@@ -0,0 +1,29 @@
+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.gatekeeper",
+    vendor_available: true,
+    imports: [
+        "android.hardware.security.keymint-V2",
+    ],
+    srcs: ["android/hardware/gatekeeper/*.aidl"],
+    stability: "vintf",
+    backend: {
+        java: {
+            platform_apis: true,
+        },
+        ndk: {
+            apps_enabled: false,
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+}
diff --git a/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/GatekeeperEnrollResponse.aidl b/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/GatekeeperEnrollResponse.aidl
new file mode 100644
index 0000000..ae64ffc
--- /dev/null
+++ b/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/GatekeeperEnrollResponse.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.gatekeeper;
+@VintfStability
+parcelable GatekeeperEnrollResponse {
+  int statusCode;
+  int timeoutMs;
+  long secureUserId;
+  byte[] data;
+}
diff --git a/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/GatekeeperVerifyResponse.aidl b/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/GatekeeperVerifyResponse.aidl
new file mode 100644
index 0000000..f55da30
--- /dev/null
+++ b/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/GatekeeperVerifyResponse.aidl
@@ -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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.gatekeeper;
+@VintfStability
+parcelable GatekeeperVerifyResponse {
+  int statusCode;
+  int timeoutMs;
+  android.hardware.security.keymint.HardwareAuthToken hardwareAuthToken;
+}
diff --git a/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/IGatekeeper.aidl b/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/IGatekeeper.aidl
new file mode 100644
index 0000000..1a6f1ff
--- /dev/null
+++ b/gatekeeper/aidl/aidl_api/android.hardware.gatekeeper/current/android/hardware/gatekeeper/IGatekeeper.aidl
@@ -0,0 +1,46 @@
+/*
+ * 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.gatekeeper;
+@SensitiveData @VintfStability
+interface IGatekeeper {
+  void deleteAllUsers();
+  void deleteUser(in int uid);
+  android.hardware.gatekeeper.GatekeeperEnrollResponse enroll(in int uid, in byte[] currentPasswordHandle, in byte[] currentPassword, in byte[] desiredPassword);
+  android.hardware.gatekeeper.GatekeeperVerifyResponse verify(in int uid, in long challenge, in byte[] enrolledPasswordHandle, in byte[] providedPassword);
+  const int STATUS_REENROLL = 1;
+  const int STATUS_OK = 0;
+  const int ERROR_GENERAL_FAILURE = -1;
+  const int ERROR_RETRY_TIMEOUT = -2;
+  const int ERROR_NOT_IMPLEMENTED = -3;
+}
diff --git a/gatekeeper/aidl/android/hardware/gatekeeper/GatekeeperEnrollResponse.aidl b/gatekeeper/aidl/android/hardware/gatekeeper/GatekeeperEnrollResponse.aidl
new file mode 100644
index 0000000..04bacf0
--- /dev/null
+++ b/gatekeeper/aidl/android/hardware/gatekeeper/GatekeeperEnrollResponse.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gatekeeper;
+
+/**
+ * Gatekeeper response to enroll requests has this structure as mandatory part
+ */
+@VintfStability
+parcelable GatekeeperEnrollResponse {
+    /**
+     * Request completion status
+     */
+    int statusCode;
+    /**
+     * Retry timeout in ms, if code == ERROR_RETRY_TIMEOUT
+     * otherwise unused (0)
+     */
+    int timeoutMs;
+    /**
+     * secure user id.
+     */
+    long secureUserId;
+    /**
+     * optional crypto blob. Opaque to Android system.
+     */
+    byte[] data;
+}
diff --git a/gatekeeper/aidl/android/hardware/gatekeeper/GatekeeperVerifyResponse.aidl b/gatekeeper/aidl/android/hardware/gatekeeper/GatekeeperVerifyResponse.aidl
new file mode 100644
index 0000000..bcf2d76
--- /dev/null
+++ b/gatekeeper/aidl/android/hardware/gatekeeper/GatekeeperVerifyResponse.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gatekeeper;
+
+import android.hardware.security.keymint.HardwareAuthToken;
+
+/**
+ * Gatekeeper response to verify requests has this structure as mandatory part
+ */
+@VintfStability
+parcelable GatekeeperVerifyResponse {
+    /**
+     * Request completion status
+     */
+    int statusCode;
+    /**
+     * Retry timeout in ms, if code == ERROR_RETRY_TIMEOUT
+     * otherwise unused (0)
+     */
+    int timeoutMs;
+    /**
+     * On successful verification of the password,
+     * IGatekeeper implementations must return hardware auth token
+     * in the response.
+     */
+    HardwareAuthToken hardwareAuthToken;
+}
diff --git a/gatekeeper/aidl/android/hardware/gatekeeper/IGatekeeper.aidl b/gatekeeper/aidl/android/hardware/gatekeeper/IGatekeeper.aidl
new file mode 100644
index 0000000..927293e
--- /dev/null
+++ b/gatekeeper/aidl/android/hardware/gatekeeper/IGatekeeper.aidl
@@ -0,0 +1,146 @@
+/*
+ * 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.gatekeeper;
+
+import android.hardware.gatekeeper.GatekeeperEnrollResponse;
+import android.hardware.gatekeeper.GatekeeperVerifyResponse;
+
+@VintfStability
+@SensitiveData
+interface IGatekeeper {
+    /**
+     * enroll and verify binder calls may return a ServiceSpecificException
+     * with the following error codes.
+     */
+    /* Success, but upper layers should re-enroll the verified password due to a version change. */
+    const int STATUS_REENROLL = 1;
+    /* operation is successful */
+    const int STATUS_OK = 0;
+    /* operation is successful. */
+    const int ERROR_GENERAL_FAILURE = -1;
+    /* operation should  be retried after timeout. */
+    const int ERROR_RETRY_TIMEOUT = -2;
+    /* operation is not implemented. */
+    const int ERROR_NOT_IMPLEMENTED = -3;
+
+    /**
+     * Deletes all the enrolled_password_handles for all uid's. Once called,
+     * no users must be enrolled on the device.
+     * This is an optional method.
+     *
+     * Service status return:
+     *
+     * OK if all the users are deleted successfully.
+     * ERROR_GENERAL_FAILURE on failure.
+     * ERROR_NOT_IMPLEMENTED if not implemented.
+     */
+    void deleteAllUsers();
+
+    /**
+     * Deletes the enrolledPasswordHandle associated with the uid. Once deleted
+     * the user cannot be verified anymore.
+     * This is an optional method.
+     *
+     * Service status return:
+     *
+     * OK if user is deleted successfully.
+     * ERROR_GENERAL_FAILURE on failure.
+     * ERROR_NOT_IMPLEMENTED if not implemented.
+     *
+     * @param uid The Android user identifier
+     */
+    void deleteUser(in int uid);
+
+    /**
+     * Enrolls desiredPassword, which may be derived from a user selected pin
+     * or password, with the private key used only for enrolling authentication
+     * factor data.
+     *
+     * If there was already a password enrolled, current password handle must be
+     * passed in currentPasswordHandle, and current password must be passed in
+     * currentPassword. Valid currentPassword must verify() against
+     * currentPasswordHandle.
+     *
+     * Service status return:
+     *
+     * OK if password is enrolled successfully.
+     * ERROR_GENERAL_FAILURE on failure.
+     * ERROR_NOT_IMPLEMENTED if not implemented.
+     *
+     * @param uid The Android user identifier
+     *
+     * @param currentPasswordHandle The currently enrolled password handle the user
+     *    wants to replace. May be empty only if there's no currently enrolled
+     *    password. Otherwise must be non-empty.
+     *
+     * @param currentPassword The user's current password in plain text.
+     *    it MUST verify against current_password_handle if the latter is not-empty
+     *
+     * @param desiredPassword The new password the user wishes to enroll in
+     *    plaintext.
+     *
+     * @return
+     *    On success, data buffer must contain the new password handle referencing
+     *    the password provided in desiredPassword.
+     *    This buffer can be used on subsequent calls to enroll or
+     *    verify. response.statusCode must contain either ERROR_RETRY_TIMEOUT or
+     *    STATUS_OK. On error, this buffer must be empty. This method may return
+     *    ERROR_GENERAL_FAILURE on failure.
+     *    If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero.
+     */
+    GatekeeperEnrollResponse enroll(in int uid, in byte[] currentPasswordHandle,
+            in byte[] currentPassword, in byte[] desiredPassword);
+
+    /**
+     * Verifies that providedPassword matches enrolledPasswordHandle.
+     *
+     * Implementations of this module may retain the result of this call
+     * to attest to the recency of authentication.
+     *
+     * On success, returns verification token in response.data, which shall be
+     * usable to attest password verification to other trusted services.
+     *
+     * Service status return:
+     *
+     * OK if password is enrolled successfully.
+     * ERROR_GENERAL_FAILURE on failure.
+     * ERROR_NOT_IMPLEMENTED if not implemented.
+     *
+     * @param uid The Android user identifier
+     *
+     * @param challenge An optional challenge to authenticate against, or 0.
+     *    Used when a separate authenticator requests password verification,
+     *    or for transactional password authentication.
+     *
+     * @param enrolledPasswordHandle The currently enrolled password handle that
+     *    user wishes to verify against. Must be non-empty.
+     *
+     * @param providedPassword The plaintext password to be verified against the
+     *    enrolledPasswordHandle
+     *
+     * @return
+     *    On success, a HardwareAuthToken resulting from this verification is returned.
+     *    response.statusCode must contain either ERROR_RETRY_TIMEOUT or
+     *    or STATUS_REENROLL or STATUS_OK.
+     *    On error, data buffer must be empty.
+     *    This method may return ERROR_GENERAL_FAILURE on failure.
+     *    If password re-enrollment is necessary, it must return STATUS_REENROLL.
+     *    If ERROR_RETRY_TIMEOUT is returned, response.timeout must be non-zero.
+     */
+    GatekeeperVerifyResponse verify(in int uid, in long challenge, in byte[] enrolledPasswordHandle,
+            in byte[] providedPassword);
+}
diff --git a/gatekeeper/aidl/vts/functional/Android.bp b/gatekeeper/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..2fa80de
--- /dev/null
+++ b/gatekeeper/aidl/vts/functional/Android.bp
@@ -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.
+//
+
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalGatekeeperTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+        "keymint_use_latest_hal_aidl_ndk_shared",
+    ],
+    srcs: ["VtsHalGatekeeperTargetTest.cpp"],
+    shared_libs: [
+        "libbinder_ndk",
+        "libbase",
+    ],
+    static_libs: ["android.hardware.gatekeeper-V1-ndk"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp b/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp
new file mode 100644
index 0000000..c89243b
--- /dev/null
+++ b/gatekeeper/aidl/vts/functional/VtsHalGatekeeperTargetTest.cpp
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "gatekeeper_aidl_hal_test"
+
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <cmath>
+#include <string>
+#include <vector>
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/gatekeeper/GatekeeperEnrollResponse.h>
+#include <aidl/android/hardware/gatekeeper/GatekeeperVerifyResponse.h>
+#include <aidl/android/hardware/gatekeeper/IGatekeeper.h>
+#include <aidl/android/hardware/security/keymint/HardwareAuthToken.h>
+#include <android-base/endian.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <hardware/hw_auth_token.h>
+
+#include <log/log.h>
+
+using aidl::android::hardware::gatekeeper::GatekeeperEnrollResponse;
+using aidl::android::hardware::gatekeeper::GatekeeperVerifyResponse;
+using aidl::android::hardware::gatekeeper::IGatekeeper;
+using aidl::android::hardware::security::keymint::HardwareAuthToken;
+using Status = ::ndk::ScopedAStatus;
+
+struct GatekeeperRequest {
+    uint32_t uid;
+    uint64_t challenge;
+    std::vector<uint8_t> curPwdHandle;
+    std::vector<uint8_t> curPwd;
+    std::vector<uint8_t> newPwd;
+    GatekeeperRequest() : uid(0), challenge(0) {}
+};
+
+// ASSERT_* macros generate return "void" internally
+// we have to use EXPECT_* if we return anything but "void"
+static void verifyAuthToken(GatekeeperVerifyResponse& rsp) {
+    uint32_t auth_type = static_cast<uint32_t>(rsp.hardwareAuthToken.authenticatorType);
+    uint64_t auth_tstamp = static_cast<uint64_t>(rsp.hardwareAuthToken.timestamp.milliSeconds);
+
+    EXPECT_EQ(HW_AUTH_PASSWORD, auth_type);
+    EXPECT_NE(UINT64_C(~0), auth_tstamp);
+    ALOGI("Authenticator ID: %016" PRIX64, rsp.hardwareAuthToken.authenticatorId);
+    EXPECT_NE(UINT32_C(0), rsp.hardwareAuthToken.userId);
+}
+
+// The main test class for Gatekeeper AIDL HAL.
+class GatekeeperAidlTest : public ::testing::TestWithParam<std::string> {
+  protected:
+    void setUid(uint32_t uid) { uid_ = uid; }
+
+    Status doEnroll(GatekeeperRequest& req, GatekeeperEnrollResponse& rsp) {
+        Status ret;
+        while (true) {
+            ret = gatekeeper_->enroll(uid_, req.curPwdHandle, req.curPwd, req.newPwd, &rsp);
+            if (ret.isOk()) break;
+            if (getReturnStatusCode(ret) != IGatekeeper::ERROR_RETRY_TIMEOUT) break;
+            ALOGI("%s: got retry code; retrying in 1 sec", __func__);
+            sleep(1);
+        }
+        return ret;
+    }
+
+    Status doVerify(GatekeeperRequest& req, GatekeeperVerifyResponse& rsp) {
+        Status ret;
+        while (true) {
+            ret = gatekeeper_->verify(uid_, req.challenge, req.curPwdHandle, req.newPwd, &rsp);
+            if (ret.isOk()) break;
+            if (getReturnStatusCode(ret) != IGatekeeper::ERROR_RETRY_TIMEOUT) break;
+            ALOGI("%s: got retry code; retrying in 1 sec", __func__);
+            sleep(1);
+        }
+        return ret;
+    }
+
+    Status doDeleteUser() { return gatekeeper_->deleteUser(uid_); }
+
+    Status doDeleteAllUsers() { return gatekeeper_->deleteAllUsers(); }
+
+    void generatePassword(std::vector<uint8_t>& password, uint8_t seed) {
+        password.resize(16);
+        memset(password.data(), seed, password.size());
+    }
+
+    void checkEnroll(GatekeeperEnrollResponse& rsp, Status& ret, bool expectSuccess) {
+        if (expectSuccess) {
+            EXPECT_TRUE(ret.isOk());
+            EXPECT_EQ(IGatekeeper::STATUS_OK, rsp.statusCode);
+            EXPECT_NE(nullptr, rsp.data.data());
+            EXPECT_GT(rsp.data.size(), UINT32_C(0));
+            EXPECT_NE(UINT32_C(0), rsp.secureUserId);
+        } else {
+            EXPECT_EQ(IGatekeeper::ERROR_GENERAL_FAILURE, getReturnStatusCode(ret));
+            EXPECT_EQ(UINT32_C(0), rsp.data.size());
+        }
+    }
+
+    void checkVerify(GatekeeperVerifyResponse& rsp, Status& ret, uint64_t challenge,
+                     bool expectSuccess) {
+        if (expectSuccess) {
+            EXPECT_TRUE(ret.isOk());
+            EXPECT_GE(rsp.statusCode, IGatekeeper::STATUS_OK);
+            EXPECT_LE(rsp.statusCode, IGatekeeper::STATUS_REENROLL);
+
+            verifyAuthToken(rsp);
+            EXPECT_EQ(challenge, rsp.hardwareAuthToken.challenge);
+        } else {
+            EXPECT_EQ(IGatekeeper::ERROR_GENERAL_FAILURE, getReturnStatusCode(ret));
+        }
+    }
+
+    void enrollNewPassword(std::vector<uint8_t>& password, GatekeeperEnrollResponse& rsp,
+                           bool expectSuccess) {
+        GatekeeperRequest req;
+        req.newPwd = password;
+        Status ret = doEnroll(req, rsp);
+        checkEnroll(rsp, ret, expectSuccess);
+    }
+
+    void verifyPassword(std::vector<uint8_t>& password, std::vector<uint8_t>& passwordHandle,
+                        uint64_t challenge, GatekeeperVerifyResponse& verifyRsp,
+                        bool expectSuccess) {
+        GatekeeperRequest verifyReq;
+
+        // build verify request for the same password (we want it to succeed)
+        verifyReq.newPwd = password;
+        // use enrolled password handle we've got
+        verifyReq.curPwdHandle = passwordHandle;
+        verifyReq.challenge = challenge;
+        Status ret = doVerify(verifyReq, verifyRsp);
+        checkVerify(verifyRsp, ret, challenge, expectSuccess);
+    }
+
+    int32_t getReturnStatusCode(const Status& result) {
+        if (!result.isOk()) {
+            if (result.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+                return result.getServiceSpecificError();
+            }
+            return IGatekeeper::ERROR_GENERAL_FAILURE;
+        }
+        return IGatekeeper::STATUS_OK;
+    }
+
+  protected:
+    std::shared_ptr<IGatekeeper> gatekeeper_;
+    uint32_t uid_;
+
+  public:
+    GatekeeperAidlTest() : uid_(0) {}
+    virtual void SetUp() override {
+        gatekeeper_ = IGatekeeper::fromBinder(
+            ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+        ASSERT_NE(nullptr, gatekeeper_.get());
+        doDeleteAllUsers();
+    }
+
+    virtual void TearDown() override { doDeleteAllUsers(); }
+};
+
+/**
+ * Ensure we can enroll new password
+ */
+TEST_P(GatekeeperAidlTest, EnrollSuccess) {
+    std::vector<uint8_t> password;
+    GatekeeperEnrollResponse rsp;
+    ALOGI("Testing Enroll (expected success)");
+    generatePassword(password, 0);
+    enrollNewPassword(password, rsp, true);
+    ALOGI("Testing Enroll done");
+}
+
+/**
+ * Ensure we can not enroll empty password
+ */
+TEST_P(GatekeeperAidlTest, EnrollNoPassword) {
+    std::vector<uint8_t> password;
+    GatekeeperEnrollResponse rsp;
+    ALOGI("Testing Enroll (expected failure)");
+    enrollNewPassword(password, rsp, false);
+    ALOGI("Testing Enroll done");
+}
+
+/**
+ * Ensure we can successfully verify previously enrolled password
+ */
+TEST_P(GatekeeperAidlTest, VerifySuccess) {
+    GatekeeperEnrollResponse enrollRsp;
+    GatekeeperVerifyResponse verifyRsp;
+    std::vector<uint8_t> password;
+
+    ALOGI("Testing Enroll+Verify (expected success)");
+    generatePassword(password, 0);
+    enrollNewPassword(password, enrollRsp, true);
+    verifyPassword(password, enrollRsp.data, 1, verifyRsp, true);
+
+    ALOGI("Testing unenrolled password doesn't verify");
+    verifyRsp = {0, 0, {}};
+    generatePassword(password, 1);
+    verifyPassword(password, enrollRsp.data, 1, verifyRsp, false);
+    ALOGI("Testing Enroll+Verify done");
+}
+
+/**
+ * Ensure we can securely update password (keep the same
+ * secure user_id) if we prove we know old password
+ */
+TEST_P(GatekeeperAidlTest, TrustedReenroll) {
+    GatekeeperEnrollResponse enrollRsp;
+    GatekeeperRequest reenrollReq;
+    GatekeeperEnrollResponse reenrollRsp;
+    GatekeeperVerifyResponse verifyRsp;
+    GatekeeperVerifyResponse reenrollVerifyRsp;
+    std::vector<uint8_t> password;
+    std::vector<uint8_t> newPassword;
+
+    generatePassword(password, 0);
+
+    ALOGI("Testing Trusted Reenroll (expected success)");
+    enrollNewPassword(password, enrollRsp, true);
+    verifyPassword(password, enrollRsp.data, 0, verifyRsp, true);
+    ALOGI("Primary Enroll+Verify done");
+
+    generatePassword(newPassword, 1);
+    reenrollReq.newPwd = newPassword;
+    reenrollReq.curPwd = password;
+    reenrollReq.curPwdHandle = enrollRsp.data;
+
+    Status ret = doEnroll(reenrollReq, reenrollRsp);
+    checkEnroll(reenrollRsp, ret, true);
+    verifyPassword(newPassword, reenrollRsp.data, 0, reenrollVerifyRsp, true);
+    ALOGI("Trusted ReEnroll+Verify done");
+
+    verifyAuthToken(verifyRsp);
+    verifyAuthToken(reenrollVerifyRsp);
+    EXPECT_EQ(verifyRsp.hardwareAuthToken.userId, reenrollVerifyRsp.hardwareAuthToken.userId);
+    ALOGI("Testing Trusted Reenroll done");
+}
+
+/**
+ * Ensure we can update password (and get new
+ * secure user_id) if we don't know old password
+ */
+TEST_P(GatekeeperAidlTest, UntrustedReenroll) {
+    GatekeeperEnrollResponse enrollRsp;
+    GatekeeperEnrollResponse reenrollRsp;
+    GatekeeperVerifyResponse verifyRsp;
+    GatekeeperVerifyResponse reenrollVerifyRsp;
+    std::vector<uint8_t> password;
+    std::vector<uint8_t> newPassword;
+
+    ALOGI("Testing Untrusted Reenroll (expected success)");
+    generatePassword(password, 0);
+    enrollNewPassword(password, enrollRsp, true);
+    verifyPassword(password, enrollRsp.data, 0, verifyRsp, true);
+    ALOGI("Primary Enroll+Verify done");
+
+    generatePassword(newPassword, 1);
+    enrollNewPassword(newPassword, reenrollRsp, true);
+    verifyPassword(newPassword, reenrollRsp.data, 0, reenrollVerifyRsp, true);
+    ALOGI("Untrusted ReEnroll+Verify done");
+
+    verifyAuthToken(verifyRsp);
+    verifyAuthToken(reenrollVerifyRsp);
+    EXPECT_NE(verifyRsp.hardwareAuthToken.userId, reenrollVerifyRsp.hardwareAuthToken.userId);
+    ALOGI("Testing Untrusted Reenroll done");
+}
+
+/**
+ * Ensure we don't get successful verify with invalid data
+ */
+TEST_P(GatekeeperAidlTest, VerifyNoData) {
+    std::vector<uint8_t> password;
+    std::vector<uint8_t> passwordHandle;
+    GatekeeperVerifyResponse verifyRsp;
+
+    ALOGI("Testing Verify (expected failure)");
+    verifyPassword(password, passwordHandle, 0, verifyRsp, false);
+    ALOGI("Testing Verify done");
+}
+
+/**
+ * Ensure we can not verify password after we enrolled it and then deleted user
+ */
+TEST_P(GatekeeperAidlTest, DeleteUserTest) {
+    std::vector<uint8_t> password;
+    GatekeeperEnrollResponse enrollRsp;
+    GatekeeperVerifyResponse verifyRsp;
+    ALOGI("Testing deleteUser (expected success)");
+    setUid(10001);
+    generatePassword(password, 0);
+    enrollNewPassword(password, enrollRsp, true);
+    verifyPassword(password, enrollRsp.data, 0, verifyRsp, true);
+    ALOGI("Enroll+Verify done");
+    auto result = doDeleteUser();
+    EXPECT_TRUE(result.isOk() ||
+                (getReturnStatusCode(result) == IGatekeeper::ERROR_NOT_IMPLEMENTED));
+    ALOGI("DeleteUser done");
+    if (result.isOk()) {
+        verifyRsp = {0, 0, {}};
+        verifyPassword(password, enrollRsp.data, 0, verifyRsp, false);
+        ALOGI("Verify after Delete done (must fail)");
+    }
+    ALOGI("Testing deleteUser done: rsp=%" PRIi32, getReturnStatusCode(result));
+}
+
+/**
+ * Ensure we can not delete a user that does not exist
+ */
+TEST_P(GatekeeperAidlTest, DeleteInvalidUserTest) {
+    std::vector<uint8_t> password;
+    GatekeeperEnrollResponse enrollRsp;
+    GatekeeperVerifyResponse verifyRsp;
+    ALOGI("Testing deleteUser (expected failure)");
+    setUid(10002);
+    generatePassword(password, 0);
+    enrollNewPassword(password, enrollRsp, true);
+    verifyPassword(password, enrollRsp.data, 0, verifyRsp, true);
+    ALOGI("Enroll+Verify done");
+
+    // Delete the user
+    Status result1 = doDeleteUser();
+    EXPECT_TRUE(result1.isOk() ||
+                (getReturnStatusCode(result1) == IGatekeeper::ERROR_NOT_IMPLEMENTED));
+
+    // Delete the user again
+    Status result2 = doDeleteUser();
+    int32_t retCode2 = getReturnStatusCode(result2);
+    EXPECT_TRUE((retCode2 == IGatekeeper::ERROR_NOT_IMPLEMENTED) ||
+                (retCode2 == IGatekeeper::ERROR_GENERAL_FAILURE));
+    ALOGI("DeleteUser done");
+    ALOGI("Testing deleteUser done: rsp=%" PRIi32, retCode2);
+}
+
+/**
+ * Ensure we can not verify passwords after we enrolled them and then deleted
+ * all users
+ */
+TEST_P(GatekeeperAidlTest, DeleteAllUsersTest) {
+    struct UserData {
+        uint32_t userId;
+        std::vector<uint8_t> password;
+        GatekeeperEnrollResponse enrollRsp;
+        GatekeeperVerifyResponse verifyRsp;
+        UserData(int id) { userId = id; }
+    } users[3]{10001, 10002, 10003};
+    ALOGI("Testing deleteAllUsers (expected success)");
+
+    // enroll multiple users
+    for (size_t i = 0; i < sizeof(users) / sizeof(users[0]); ++i) {
+        setUid(users[i].userId);
+        generatePassword(users[i].password, (i % 255) + 1);
+        enrollNewPassword(users[i].password, users[i].enrollRsp, true);
+    }
+    ALOGI("Multiple users enrolled");
+
+    // verify multiple users
+    for (size_t i = 0; i < sizeof(users) / sizeof(users[0]); ++i) {
+        setUid(users[i].userId);
+        verifyPassword(users[i].password, users[i].enrollRsp.data, 0, users[i].verifyRsp, true);
+    }
+    ALOGI("Multiple users verified");
+
+    Status result = doDeleteAllUsers();
+    EXPECT_TRUE(result.isOk() ||
+                (getReturnStatusCode(result) == IGatekeeper::ERROR_NOT_IMPLEMENTED));
+    ALOGI("All users deleted");
+
+    if (result.isOk()) {
+        // verify multiple users after they are deleted; all must fail
+        for (size_t i = 0; i < sizeof(users) / sizeof(users[0]); ++i) {
+            setUid(users[i].userId);
+            users[i].verifyRsp = {0, 0, {}};
+            verifyPassword(users[i].password, users[i].enrollRsp.data, 0, users[i].verifyRsp,
+                           false);
+        }
+        ALOGI("Multiple users verified after delete (all must fail)");
+    }
+
+    ALOGI("Testing deleteAllUsers done: rsp=%" PRIi32, getReturnStatusCode(result));
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GatekeeperAidlTest);
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, GatekeeperAidlTest,
+    testing::ValuesIn(android::getAidlHalInstanceNames(IGatekeeper::descriptor)),
+    android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h
index db7e67d..5f0a176 100644
--- a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h
+++ b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h
@@ -259,19 +259,22 @@
 
         for (int i = 0; i < 3; i++) {
             const auto& plane = flex.planes[i];
-            // must have 8-bit depth
-            if (plane.bits_per_component != 8 || plane.bits_used != 8) {
+            // Must be a positive multiple of 8.
+            if (plane.bits_per_component <= 0 || (plane.bits_per_component % 8) != 0) {
                 return false;
             }
-
+            // Must be between 1 and bits_per_component, inclusive.
+            if (plane.bits_used < 1 || plane.bits_used > plane.bits_per_component) {
+                return false;
+            }
             if (plane.component == FLEX_COMPONENT_Y) {
                 // Y must not be interleaved
-                if (plane.h_increment != 1) {
+                if (plane.h_increment != 1 && plane.h_increment != 2) {
                     return false;
                 }
             } else {
                 // Cb and Cr can be interleaved
-                if (plane.h_increment != 1 && plane.h_increment != 2) {
+                if (plane.h_increment != 1 && plane.h_increment != 2 && plane.h_increment != 4) {
                     return false;
                 }
             }
diff --git a/identity/aidl/default/Android.bp b/identity/aidl/default/Android.bp
index 31ab400..a57875a 100644
--- a/identity/aidl/default/Android.bp
+++ b/identity/aidl/default/Android.bp
@@ -10,6 +10,10 @@
 cc_library_static {
     name: "android.hardware.identity-libeic-hal-common",
     vendor_available: true,
+    defaults: [
+        "identity_use_latest_hal_aidl_ndk_static",
+        "keymint_use_latest_hal_aidl_ndk_static",
+    ],
     srcs: [
         "common/IdentityCredential.cpp",
         "common/IdentityCredentialStore.cpp",
@@ -40,9 +44,7 @@
         "libsoft_attestation_cert",
         "libpuresoftkeymasterdevice",
         "android.hardware.identity-support-lib",
-        "android.hardware.identity-V4-ndk",
         "android.hardware.keymaster-V3-ndk",
-        "android.hardware.security.keymint-V2-ndk",
     ],
 }
 
@@ -83,6 +85,7 @@
     vintf_fragments: ["identity-default.xml"],
     vendor: true,
     defaults: [
+        "identity_use_latest_hal_aidl_ndk_static",
         "keymint_use_latest_hal_aidl_ndk_static",
     ],
     cflags: [
@@ -106,7 +109,6 @@
         "libsoft_attestation_cert",
         "libpuresoftkeymasterdevice",
         "android.hardware.identity-support-lib",
-        "android.hardware.identity-V4-ndk",
         "android.hardware.keymaster-V3-ndk",
         "android.hardware.identity-libeic-hal-common",
         "android.hardware.identity-libeic-library",
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index 51ab110..dd29819 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -11,6 +11,7 @@
     name: "VtsHalIdentityTargetTest",
     defaults: [
         "VtsHalTargetTestDefaults",
+        "identity_use_latest_hal_aidl_cpp_static",
         "keymint_use_latest_hal_aidl_cpp_static",
         "keymint_use_latest_hal_aidl_ndk_static",
         "use_libaidlvintf_gtest_helper_static",
@@ -46,7 +47,6 @@
         "libpuresoftkeymasterdevice",
         "android.hardware.keymaster@4.0",
         "android.hardware.identity-support-lib",
-        "android.hardware.identity-V4-cpp",
         "android.hardware.keymaster-V3-cpp",
         "android.hardware.keymaster-V3-ndk",
         "libkeymaster4support",
diff --git a/input/common/aidl/Android.bp b/input/common/aidl/Android.bp
index 390d8b5..95a14b2 100644
--- a/input/common/aidl/Android.bp
+++ b/input/common/aidl/Android.bp
@@ -9,6 +9,7 @@
 
 aidl_interface {
     name: "android.hardware.input.common",
+    host_supported: true,
     vendor_available: true,
     srcs: ["android/hardware/input/common/*.aidl"],
     stability: "vintf",
diff --git a/input/processor/aidl/Android.bp b/input/processor/aidl/Android.bp
index 354816e..773bb49 100644
--- a/input/processor/aidl/Android.bp
+++ b/input/processor/aidl/Android.bp
@@ -9,6 +9,7 @@
 
 aidl_interface {
     name: "android.hardware.input.processor",
+    host_supported: true,
     vendor_available: true,
     srcs: ["android/hardware/input/processor/*.aidl"],
     imports: [
diff --git a/power/OWNERS b/power/OWNERS
new file mode 100644
index 0000000..7229b22
--- /dev/null
+++ b/power/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 826709
+
+# ADPF virtual team
+lpy@google.com
+wvw@google.com
diff --git a/radio/aidl/OWNERS b/radio/aidl/OWNERS
new file mode 100644
index 0000000..7b01aad
--- /dev/null
+++ b/radio/aidl/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 20868
+include ../1.0/vts/OWNERS
+
diff --git a/radio/aidl/vts/OWNERS b/radio/aidl/vts/OWNERS
deleted file mode 100644
index e75c6c8..0000000
--- a/radio/aidl/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 20868
-include ../../1.0/vts/OWNERS
-
diff --git a/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl b/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
index 6954d65..6854851 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
@@ -49,8 +49,16 @@
      *         "security_level" : "tee" / "strongbox",
      *         "fused": 1 / 0,  ; 1 if secure boot is enforced for the processor that the IRPC
      *                          ; implementation is contained in. 0 otherwise.
-     *         "cert_type": "widevine" / "keymint"
+     *         "cert_type": CertificateType;
      *     }
+     *
+     *     ; A tstr identifying the type of certificate. The set of supported certificate types may
+     *     ; be extended without requiring a version bump of the HAL. Custom certificate types may
+     *     ; be used, but the provisioning server may reject the request for an unknown certificate
+     *     ; type. The currently defined certificate types are:
+     *     ;  - "widevine"
+     *     ;  - "keymint"
+     *     CertificateType = tstr
      */
     byte[] deviceInfo;
 }
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 926d105..2e4fc15 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -624,9 +624,15 @@
      *
      *   o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
      *
-     *   o The timestamp in the auth token plus the value of the Tag::AUTH_TIMEOUT must be less than
-     *     the current secure timestamp (which is a monotonic timer counting milliseconds since
-     *     boot.)
+     *   o If the device has a source of secure time, then the timestamp in the auth token plus the
+     *     value of the Tag::AUTH_TIMEOUT must be greater than the current secure timestamp (which
+     *     is a monotonic timer counting milliseconds since boot).
+     *
+     *   o If the device does not have a source of secure time, then the timestamp check should be
+     *     performed on the first update(), updateAad() or finish() invocation for the operation,
+     *     using the timeStampToken parameter provided on the invocation to indicate the current
+     *     timestamp. It may optionally also be performed on subsequent update() / updateAad() /
+     *     finish() invocations.
      *
      *   If any of these conditions are not met, begin() must return
      *   ErrorCode::KEY_USER_NOT_AUTHENTICATED.
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
index c30c183..82c8a0d 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
@@ -40,31 +40,7 @@
      *
      * == Authorization Enforcement ==
      *
-     * Key authorization enforcement is performed primarily in begin().  The one exception is the
-     * case where the key has:
-     *
-     * o One or more Tag::USER_SECURE_IDs, and
-     *
-     * o Does not have a Tag::AUTH_TIMEOUT
-     *
-     * In this case, the key requires an authorization per operation, and the update method must
-     * receive a non-null and valid HardwareAuthToken.  For the auth token to be valid, all of the
-     * following has to be true:
-     *
-     *   o The HMAC field must validate correctly.
-     *
-     *   o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of
-     *     the secure ID values in the token.
-     *
-     *   o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
-     *
-     *   o The challenge field in the auth token must contain the value returned from
-     *     IKeyMintDevice::begin(), given by the challenge field of the BeginResult structure.
-     *
-     *   If any of these conditions are not met, updateAad() must return
-     *   ErrorCode::KEY_USER_NOT_AUTHENTICATED.
-     *
-     * The caller must provide the auth token on every call to updateAad(), update() and finish().
+     * See the Authorization Enforcement section for the update() method.
      *
      *
      * For GCM encryption, the AEAD tag must be appended to the ciphertext by finish().  During
@@ -104,16 +80,22 @@
      *
      * == Authorization Enforcement ==
      *
-     * Key authorization enforcement is performed primarily in IKeyMintDevice::begin().  The one
-     * exception is the case where the key has:
+     * Key authorization enforcement is performed primarily in IKeyMintDevice::begin().  There are
+     * two exceptions to this:
      *
-     * o One or more Tag::USER_SECURE_IDs, and
+     *  1) Key with USER_SECURE_IDs but no AUTH_TIMEOUT
      *
-     * o Does not have a Tag::AUTH_TIMEOUT
+     *  2) Key with USER_SECURE_IDs and AUTH_TIMEOUT, but the device does not support secure time.
      *
-     * In this case, the key requires an authorization per operation, and the update method must
-     * receive a non-empty and valid HardwareAuthToken.  For the auth token to be valid, all of the
-     * following has to be true:
+     * The first exception is the case where the key:
+     *
+     *   o Has one or more Tag::USER_SECURE_IDs, and
+     *
+     *   o Does not have a Tag::AUTH_TIMEOUT
+     *
+     * In this case, the key requires an authorization per operation, and update() / updateAad() /
+     * finish() methods must receive a non-null and valid HardwareAuthToken.  For the auth token to
+     * be valid, all of the following has to be true:
      *
      *   o The HMAC field must validate correctly.
      *
@@ -125,10 +107,47 @@
      *   o The challenge field in the auth token must contain the challenge value contained in the
      *     BeginResult returned from IKeyMintDevice::begin().
      *
-     *   If any of these conditions are not met, update() must return
+     *   If any of these conditions are not met, the method must return
      *   ErrorCode::KEY_USER_NOT_AUTHENTICATED.
      *
-     * The caller must provide the auth token on every call to update() and finish().
+     * The caller must provide the auth token on every call to update(), updateAad() and finish().
+     *
+     *
+     * The second exception is the case where the key:
+     *
+     *   o Has one or more Tag::USER_SECURE_IDs, and
+     *
+     *   o Has a Tag::AUTH_TIMEOUT value, but the device does not have a source of secure time (as
+     *     indicated by the KeyMintHardwareInfo.timestampTokenRequired field).
+     *
+     * In this case, the key requires an per-operation authorization on the first call to update(),
+     * updateAad() or finish() for the operation, using the provided timeStampToken as a source of
+     * secure time.  For this timeStampToken to be valid, all of the following has to be true:
+     *
+     *   o The HMAC field must validate correctly.
+     *
+     *   o The challenge field in the auth token must contain the challenge value contained in the
+     *     BeginResult returned from IKeyMintDevice::begin().
+     *
+     * The resulting secure time value is then used to authenticate the HardwareAuthToken. For the
+     * auth token to be valid, all of the following has to be true:
+     *
+     *   o The HMAC field must validate correctly.
+     *
+     *   o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of
+     *     the secure ID values in the token.
+     *
+     *   o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
+     *
+     *   o The challenge field in the auth token must contain the challenge value contained in the
+     *     BeginResult returned from IKeyMintDevice::begin().
+     *
+     *   o The timestamp in the auth token plus the value of the Tag::AUTH_TIMEOUT must be greater
+     *     than the provided secure timestamp.
+
+     *   If any of these conditions are not met, the method must return
+     *   ErrorCode::KEY_USER_NOT_AUTHENTICATED.
+     *
      *
      * -- RSA keys --
      *
@@ -187,24 +206,7 @@
      * Key authorization enforcement is performed primarily in begin().  The exceptions are
      * authorization per operation keys and confirmation-required keys.
      *
-     * Authorization per operation keys are the case where the key has one or more
-     * Tag::USER_SECURE_IDs, and does not have a Tag::AUTH_TIMEOUT.  In this case, the key requires
-     * an authorization per operation, and the finish method must receive a non-empty and valid
-     * authToken.  For the auth token to be valid, all of the following has to be true:
-     *
-     *   o The HMAC field must validate correctly.
-     *
-     *   o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of
-     *     the secure ID values in the token.
-     *
-     *   o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
-     *
-     *   o The challenge field in the auth token must contain the operation challenge.
-     *
-     *   If any of these conditions are not met, update() must return
-     *   ErrorCode::KEY_USER_NOT_AUTHENTICATED.
-     *
-     * The caller must provide the auth token on every call to update() and finish().
+     * Authorization per operation keys must be authorized as described for the update() method.
      *
      * Confirmation-required keys are keys that were generated with
      * Tag::TRUSTED_CONFIRMATION_REQUIRED.  For these keys, when doing a signing operation the
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
index 97f7a9e..77df99f 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -151,7 +151,8 @@
 
     /**
      * This method has been removed in version 3 of the HAL. The header is kept around for
-     * backwards compatibility purposes. Calling this method should return STATUS_REMOVED on v3.
+     * backwards compatibility purposes. From v3, this method should raise a
+     * ServiceSpecificException with an error code of STATUS_REMOVED.
      *
      * For v1 and v2 implementations:
      * generateCertificateRequest creates a certificate request to be sent to the provisioning
@@ -378,8 +379,8 @@
      *                                      ; Last certificate corresponds to KeyMint's DICE key.
      * ]
      *
-     * ; This is the signed payload for each entry in the DCC. Note that the "Configuration
-     * ; Input Values" described by the Open Profile are not used here. Instead, the Dcc
+     * ; This is the signed payload for each entry in the DICE chain. Note that the "Configuration
+     * ; Input Values" described by the Open Profile are not used here. Instead, the DICE chain
      * ; defines its own configuration values for the Configuration Descriptor field. See
      * ; the Open Profile for DICE for more details on the fields. SHA256 and SHA512 are acceptable
      * ; hash algorithms. The digest bstr values in the payload are the digest values without any
@@ -408,8 +409,8 @@
      *     -4670551 : bstr,                         ; Mode
      * }
      *
-     * ; Each entry in the Dcc is a DiceChainEntryPayload signed by the key from the previous entry
-     * ; in the Dcc array.
+     * ; Each entry in the DICE chain is a DiceChainEntryPayload signed by the key from the previous
+     * ; entry in the DICE chain array.
      * DiceChainEntry = [                            ; COSE_Sign1 (untagged)
      *     protected : bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
      *     unprotected: {},
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 7184613..e1f65fe 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <memory>
+#include <string>
 #define LOG_TAG "VtsRemotelyProvisionableComponentTests"
 
 #include <AndroidRemotelyProvisionedComponentDevice.h>
@@ -30,6 +32,7 @@
 #include <openssl/ec_key.h>
 #include <openssl/x509.h>
 #include <remote_prov/remote_prov_utils.h>
+#include <optional>
 #include <set>
 #include <vector>
 
@@ -57,22 +60,6 @@
 using namespace remote_prov;
 using namespace keymaster;
 
-std::set<std::string> getAllowedVbStates() {
-    return {"green", "yellow", "orange"};
-}
-
-std::set<std::string> getAllowedBootloaderStates() {
-    return {"locked", "unlocked"};
-}
-
-std::set<std::string> getAllowedSecurityLevels() {
-    return {"tee", "strongbox"};
-}
-
-std::set<std::string> getAllowedAttIdStates() {
-    return {"locked", "open"};
-}
-
 bytevec string_to_bytevec(const char* s) {
     const uint8_t* p = reinterpret_cast<const uint8_t*>(s);
     return bytevec(p, p + strlen(s));
@@ -382,157 +369,6 @@
         }
     }
 
-    ErrMsgOr<bytevec> getSessionKey(ErrMsgOr<std::pair<bytevec, bytevec>>& senderPubkey) {
-        if (rpcHardwareInfo.supportedEekCurve == RpcHardwareInfo::CURVE_25519 ||
-            rpcHardwareInfo.supportedEekCurve == RpcHardwareInfo::CURVE_NONE) {
-            return x25519_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
-                                         senderPubkey->first, false /* senderIsA */);
-        } else {
-            return ECDH_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
-                                       senderPubkey->first, false /* senderIsA */);
-        }
-    }
-
-    void checkProtectedData(const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
-                            const bytevec& keysToSignMac, const ProtectedData& protectedData,
-                            std::vector<BccEntryData>* bccOutput = nullptr) {
-        auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
-        ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
-        ASSERT_TRUE(parsedProtectedData->asArray());
-        ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
-
-        auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
-        ASSERT_TRUE(senderPubkey) << senderPubkey.message();
-        EXPECT_EQ(senderPubkey->second, eekId_);
-
-        auto sessionKey = getSessionKey(senderPubkey);
-        ASSERT_TRUE(sessionKey) << sessionKey.message();
-
-        auto protectedDataPayload =
-                decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
-        ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
-
-        auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
-        ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
-        ASSERT_TRUE(parsedPayload->asArray());
-        // Strongbox may contain additional certificate chain.
-        EXPECT_LE(parsedPayload->asArray()->size(), 3U);
-
-        auto& signedMac = parsedPayload->asArray()->get(0);
-        auto& bcc = parsedPayload->asArray()->get(1);
-        ASSERT_TRUE(signedMac && signedMac->asArray());
-        ASSERT_TRUE(bcc && bcc->asArray());
-
-        // BCC is [ pubkey, + BccEntry]
-        auto bccContents = validateBcc(bcc->asArray());
-        ASSERT_TRUE(bccContents) << "\n" << bccContents.message() << "\n" << prettyPrint(bcc.get());
-        ASSERT_GT(bccContents->size(), 0U);
-
-        auto [deviceInfoMap, __2, deviceInfoErrMsg] = cppbor::parse(deviceInfo.deviceInfo);
-        ASSERT_TRUE(deviceInfoMap) << "Failed to parse deviceInfo: " << deviceInfoErrMsg;
-        ASSERT_TRUE(deviceInfoMap->asMap());
-        checkDeviceInfo(deviceInfoMap->asMap(), deviceInfo.deviceInfo);
-        auto& signingKey = bccContents->back().pubKey;
-        deviceInfoMap->asMap()->canonicalize();
-        auto macKey = verifyAndParseCoseSign1(signedMac->asArray(), signingKey,
-                                              cppbor::Array()  // SignedMacAad
-                                                      .add(challenge_)
-                                                      .add(std::move(deviceInfoMap))
-                                                      .add(keysToSignMac)
-                                                      .encode());
-        ASSERT_TRUE(macKey) << macKey.message();
-
-        auto coseMac0 = cppbor::Array()
-                                .add(cppbor::Map()  // protected
-                                             .add(ALGORITHM, HMAC_256)
-                                             .canonicalize()
-                                             .encode())
-                                .add(cppbor::Map())        // unprotected
-                                .add(keysToSign.encode())  // payload (keysToSign)
-                                .add(keysToSignMac);       // tag
-
-        auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
-        ASSERT_TRUE(macPayload) << macPayload.message();
-
-        if (bccOutput) {
-            *bccOutput = std::move(*bccContents);
-        }
-    }
-
-    void checkType(const cppbor::Map* devInfo, uint8_t majorType, std::string entryName) {
-        const auto& val = devInfo->get(entryName);
-        ASSERT_TRUE(val) << entryName << " does not exist";
-        ASSERT_EQ(val->type(), majorType) << entryName << " has the wrong type.";
-        switch (majorType) {
-            case cppbor::TSTR:
-                EXPECT_GT(val->asTstr()->value().size(), 0);
-                break;
-            case cppbor::BSTR:
-                EXPECT_GT(val->asBstr()->value().size(), 0);
-                break;
-            default:
-                break;
-        }
-    }
-
-    void checkDeviceInfo(const cppbor::Map* deviceInfo, bytevec deviceInfoBytes) {
-        EXPECT_EQ(deviceInfo->clone()->asMap()->canonicalize().encode(), deviceInfoBytes)
-                << "DeviceInfo ordering is non-canonical.";
-        const auto& version = deviceInfo->get("version");
-        ASSERT_TRUE(version);
-        ASSERT_TRUE(version->asUint());
-        RpcHardwareInfo info;
-        provisionable_->getHardwareInfo(&info);
-        ASSERT_EQ(version->asUint()->value(), info.versionNumber);
-        std::set<std::string> allowList;
-        switch (version->asUint()->value()) {
-            // These fields became mandated in version 2.
-            case 2:
-                checkType(deviceInfo, cppbor::TSTR, "brand");
-                checkType(deviceInfo, cppbor::TSTR, "manufacturer");
-                checkType(deviceInfo, cppbor::TSTR, "product");
-                checkType(deviceInfo, cppbor::TSTR, "model");
-                checkType(deviceInfo, cppbor::TSTR, "device");
-                // TODO: Refactor the KeyMint code that validates these fields and include it here.
-                checkType(deviceInfo, cppbor::TSTR, "vb_state");
-                allowList = getAllowedVbStates();
-                EXPECT_NE(allowList.find(deviceInfo->get("vb_state")->asTstr()->value()),
-                          allowList.end());
-                checkType(deviceInfo, cppbor::TSTR, "bootloader_state");
-                allowList = getAllowedBootloaderStates();
-                EXPECT_NE(allowList.find(deviceInfo->get("bootloader_state")->asTstr()->value()),
-                          allowList.end());
-                checkType(deviceInfo, cppbor::BSTR, "vbmeta_digest");
-                checkType(deviceInfo, cppbor::UINT, "system_patch_level");
-                checkType(deviceInfo, cppbor::UINT, "boot_patch_level");
-                checkType(deviceInfo, cppbor::UINT, "vendor_patch_level");
-                checkType(deviceInfo, cppbor::UINT, "fused");
-                EXPECT_LT(deviceInfo->get("fused")->asUint()->value(), 2);  // Must be 0 or 1.
-                checkType(deviceInfo, cppbor::TSTR, "security_level");
-                allowList = getAllowedSecurityLevels();
-                EXPECT_NE(allowList.find(deviceInfo->get("security_level")->asTstr()->value()),
-                          allowList.end());
-                if (deviceInfo->get("security_level")->asTstr()->value() == "tee") {
-                    checkType(deviceInfo, cppbor::TSTR, "os_version");
-                }
-                break;
-            case 1:
-                checkType(deviceInfo, cppbor::TSTR, "security_level");
-                allowList = getAllowedSecurityLevels();
-                EXPECT_NE(allowList.find(deviceInfo->get("security_level")->asTstr()->value()),
-                          allowList.end());
-                if (version->asUint()->value() == 1) {
-                    checkType(deviceInfo, cppbor::TSTR, "att_id_state");
-                    allowList = getAllowedAttIdStates();
-                    EXPECT_NE(allowList.find(deviceInfo->get("att_id_state")->asTstr()->value()),
-                              allowList.end());
-                }
-                break;
-            default:
-                FAIL() << "Unrecognized version: " << version->asUint()->value();
-        }
-    }
-
     bytevec eekId_;
     size_t testEekLength_;
     EekChain testEekChain_;
@@ -559,7 +395,10 @@
                 &protectedData, &keysToSignMac);
         ASSERT_TRUE(status.isOk()) << status.getMessage();
 
-        checkProtectedData(deviceInfo, cppbor::Array(), keysToSignMac, protectedData);
+        auto result = verifyProductionProtectedData(
+                deviceInfo, cppbor::Array(), keysToSignMac, protectedData, testEekChain_, eekId_,
+                rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
+        ASSERT_TRUE(result) << result.message();
     }
 }
 
@@ -581,22 +420,24 @@
             &protectedData, &keysToSignMac);
     ASSERT_TRUE(status.isOk()) << status.getMessage();
 
-    std::vector<BccEntryData> firstBcc;
-    checkProtectedData(deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData,
-                       &firstBcc);
+    auto firstBcc = verifyProductionProtectedData(
+            deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
+            eekId_, rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
+    ASSERT_TRUE(firstBcc) << firstBcc.message();
 
     status = provisionable_->generateCertificateRequest(
             testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
     ASSERT_TRUE(status.isOk()) << status.getMessage();
 
-    std::vector<BccEntryData> secondBcc;
-    checkProtectedData(deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData,
-                       &secondBcc);
+    auto secondBcc = verifyProductionProtectedData(
+            deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
+            eekId_, rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
+    ASSERT_TRUE(secondBcc) << secondBcc.message();
 
     // Verify that none of the keys in the first BCC are repeated in the second one.
-    for (const auto& i : firstBcc) {
-        for (auto& j : secondBcc) {
+    for (const auto& i : *firstBcc) {
+        for (auto& j : *secondBcc) {
             ASSERT_THAT(i.pubKey, testing::Not(testing::ElementsAreArray(j.pubKey)))
                     << "Found a repeated pubkey in two generateCertificateRequest test mode calls";
         }
@@ -639,7 +480,10 @@
                 &keysToSignMac);
         ASSERT_TRUE(status.isOk()) << status.getMessage();
 
-        checkProtectedData(deviceInfo, cborKeysToSign_, keysToSignMac, protectedData);
+        auto result = verifyProductionProtectedData(
+                deviceInfo, cborKeysToSign_, keysToSignMac, protectedData, testEekChain_, eekId_,
+                rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
+        ASSERT_TRUE(result) << result.message();
     }
 }
 
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
index bf2ab02..3f48320 100644
--- a/security/keymint/support/Android.bp
+++ b/security/keymint/support/Android.bp
@@ -65,6 +65,7 @@
     ],
     shared_libs: [
         "libbase",
+        "libbinder_ndk",
         "libcppbor_external",
         "libcppcose_rkp",
         "libcrypto",
diff --git a/security/keymint/support/include/remote_prov/remote_prov_utils.h b/security/keymint/support/include/remote_prov/remote_prov_utils.h
index f3b8608..9ea20ac 100644
--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -16,7 +16,9 @@
 
 #pragma once
 
+#include <memory>
 #include <vector>
+#include "aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h"
 
 #include <keymaster/cppcose/cppcose.h>
 
@@ -139,4 +141,40 @@
 JsonOutput jsonEncodeCsrWithBuild(const std::string instance_name,
                                   const cppbor::Array& csr);
 
+/**
+ * Parses a DeviceInfo structure from the given CBOR data. The parsed data is then validated to
+ * ensure it contains the minimum required data at the time of manufacturing. This is only a
+ * partial validation, as some fields may not be provisioned yet at the time this information
+ * is parsed in the manufacturing process.
+ */
+ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateFactoryDeviceInfo(
+        const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable);
+
+/**
+ * Parses a DeviceInfo structure from the given CBOR data. The parsed data is then validated to
+ * ensure it is formatted correctly and that it contains the required values for Remote Key
+ * Provisioning. This is a full validation, and assumes the device is provisioned as if it is
+ * suitable for the end user.
+ */
+ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateProductionDeviceInfo(
+        const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable);
+
+/**
+ * Verify the protected data as if the device is still early in the factory process and may not
+ * have all device identifiers provisioned yet.
+ */
+ErrMsgOr<std::vector<BccEntryData>> verifyFactoryProtectedData(
+        const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
+        const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
+        const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
+        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge);
+/**
+ * Verify the protected data as if the device is a final production sample.
+ */
+ErrMsgOr<std::vector<BccEntryData>> verifyProductionProtectedData(
+        const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
+        const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
+        const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
+        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge);
+
 }  // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index 0dbea5b..0651496 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -15,7 +15,11 @@
  */
 
 #include <iterator>
+#include <memory>
+#include <set>
+#include <string>
 #include <tuple>
+#include "aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h"
 
 #include <aidl/android/hardware/security/keymint/RpcHardwareInfo.h>
 #include <android-base/properties.h>
@@ -441,4 +445,293 @@
     return JsonOutput::Ok(Json::writeString(factory, json));
 }
 
-}  // namespace aidl::android::hardware::security::keymint::remote_prov
+std::string checkMapEntry(bool isFactory, const cppbor::Map& devInfo, cppbor::MajorType majorType,
+                          const std::string& entryName) {
+    const std::unique_ptr<cppbor::Item>& val = devInfo.get(entryName);
+    if (!val) {
+        return entryName + " is missing.\n";
+    }
+    if (val->type() != majorType) {
+        return entryName + " has the wrong type.\n";
+    }
+    if (isFactory) {
+        return "";
+    }
+    switch (majorType) {
+        case cppbor::TSTR:
+            if (val->asTstr()->value().size() <= 0) {
+                return entryName + " is present but the value is empty.\n";
+            }
+            break;
+        case cppbor::BSTR:
+            if (val->asBstr()->value().size() <= 0) {
+                return entryName + " is present but the value is empty.\n";
+            }
+            break;
+        default:
+            break;
+    }
+    return "";
+}
+
+std::string checkMapEntry(bool isFactory, const cppbor::Map& devInfo, cppbor::MajorType majorType,
+                          const std::string& entryName, const cppbor::Array& allowList) {
+    std::string error = checkMapEntry(isFactory, devInfo, majorType, entryName);
+    if (!error.empty()) {
+        return error;
+    }
+
+    if (isFactory) {
+        return "";
+    }
+
+    const std::unique_ptr<cppbor::Item>& val = devInfo.get(entryName);
+    for (auto i = allowList.begin(); i != allowList.end(); ++i) {
+        if (**i == *val) {
+            return "";
+        }
+    }
+    return entryName + " has an invalid value.\n";
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateDeviceInfo(
+        const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable,
+        bool isFactory) {
+    const cppbor::Array kValidVbStates = {"green", "yellow", "orange"};
+    const cppbor::Array kValidBootloaderStates = {"locked", "unlocked"};
+    const cppbor::Array kValidSecurityLevels = {"tee", "strongbox"};
+    const cppbor::Array kValidAttIdStates = {"locked", "open"};
+    const cppbor::Array kValidFused = {0, 1};
+
+    struct AttestationIdEntry {
+        const char* id;
+        bool alwaysValidate;
+    };
+    constexpr AttestationIdEntry kAttestationIdEntrySet[] = {{"brand", false},
+                                                             {"manufacturer", true},
+                                                             {"product", false},
+                                                             {"model", false},
+                                                             {"device", false}};
+
+    auto [parsedVerifiedDeviceInfo, ignore1, errMsg] = cppbor::parse(deviceInfoBytes);
+    if (!parsedVerifiedDeviceInfo) {
+        return errMsg;
+    }
+
+    std::unique_ptr<cppbor::Map> parsed(parsedVerifiedDeviceInfo->asMap());
+    if (!parsed) {
+        return "DeviceInfo must be a CBOR map.";
+    }
+    parsedVerifiedDeviceInfo.release();
+
+    if (parsed->clone()->asMap()->canonicalize().encode() != deviceInfoBytes) {
+        return "DeviceInfo ordering is non-canonical.";
+    }
+    const std::unique_ptr<cppbor::Item>& version = parsed->get("version");
+    if (!version) {
+        return "Device info is missing version";
+    }
+    if (!version->asUint()) {
+        return "version must be an unsigned integer";
+    }
+    RpcHardwareInfo info;
+    provisionable->getHardwareInfo(&info);
+    if (version->asUint()->value() != info.versionNumber) {
+        return "DeviceInfo version (" + std::to_string(version->asUint()->value()) +
+               ") does not match the remotely provisioned component version (" +
+               std::to_string(info.versionNumber) + ").";
+    }
+    std::string error;
+    switch (version->asUint()->value()) {
+        case 2:
+            for (const auto& entry : kAttestationIdEntrySet) {
+                error += checkMapEntry(isFactory && !entry.alwaysValidate, *parsed, cppbor::TSTR,
+                                       entry.id);
+            }
+            if (!error.empty()) {
+                return error +
+                       "Attestation IDs are missing or malprovisioned. If this test is being\n"
+                       "run against an early proto or EVT build, this error is probably WAI\n"
+                       "and indicates that Device IDs were not provisioned in the factory. If\n"
+                       "this error is returned on a DVT or later build revision, then\n"
+                       "something is likely wrong with the factory provisioning process.";
+            }
+            // TODO: Refactor the KeyMint code that validates these fields and include it here.
+            error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "vb_state", kValidVbStates);
+            error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "bootloader_state",
+                                   kValidBootloaderStates);
+            error += checkMapEntry(isFactory, *parsed, cppbor::BSTR, "vbmeta_digest");
+            error += checkMapEntry(isFactory, *parsed, cppbor::UINT, "system_patch_level");
+            error += checkMapEntry(isFactory, *parsed, cppbor::UINT, "boot_patch_level");
+            error += checkMapEntry(isFactory, *parsed, cppbor::UINT, "vendor_patch_level");
+            error += checkMapEntry(isFactory, *parsed, cppbor::UINT, "fused", kValidFused);
+            error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "security_level",
+                                   kValidSecurityLevels);
+            if (parsed->get("security_level") && parsed->get("security_level")->asTstr() &&
+                parsed->get("security_level")->asTstr()->value() == "tee") {
+                error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "os_version");
+            }
+            break;
+        case 1:
+            error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "security_level",
+                                   kValidSecurityLevels);
+            error += checkMapEntry(isFactory, *parsed, cppbor::TSTR, "att_id_state",
+                                   kValidAttIdStates);
+            break;
+        default:
+            return "Unrecognized version: " + std::to_string(version->asUint()->value());
+    }
+
+    if (!error.empty()) {
+        return error;
+    }
+
+    return std::move(parsed);
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateFactoryDeviceInfo(
+        const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable) {
+    return parseAndValidateDeviceInfo(deviceInfoBytes, provisionable, /*isFactory=*/true);
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Map>> parseAndValidateProductionDeviceInfo(
+        const std::vector<uint8_t>& deviceInfoBytes, IRemotelyProvisionedComponent* provisionable) {
+    return parseAndValidateDeviceInfo(deviceInfoBytes, provisionable, /*isFactory=*/false);
+}
+
+ErrMsgOr<bytevec> getSessionKey(ErrMsgOr<std::pair<bytevec, bytevec>>& senderPubkey,
+                                const EekChain& eekChain, int32_t supportedEekCurve) {
+    if (supportedEekCurve == RpcHardwareInfo::CURVE_25519 ||
+        supportedEekCurve == RpcHardwareInfo::CURVE_NONE) {
+        return x25519_HKDF_DeriveKey(eekChain.last_pubkey, eekChain.last_privkey,
+                                     senderPubkey->first, false /* senderIsA */);
+    } else {
+        return ECDH_HKDF_DeriveKey(eekChain.last_pubkey, eekChain.last_privkey, senderPubkey->first,
+                                   false /* senderIsA */);
+    }
+}
+
+ErrMsgOr<std::vector<BccEntryData>> verifyProtectedData(
+        const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
+        const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
+        const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
+        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge,
+        bool isFactory) {
+    auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
+    if (!parsedProtectedData) {
+        return protDataErrMsg;
+    }
+    if (!parsedProtectedData->asArray()) {
+        return "Protected data is not a CBOR array.";
+    }
+    if (parsedProtectedData->asArray()->size() != kCoseEncryptEntryCount) {
+        return "The protected data COSE_encrypt structure must have " +
+               std::to_string(kCoseEncryptEntryCount) + " entries, but it only has " +
+               std::to_string(parsedProtectedData->asArray()->size());
+    }
+
+    auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
+    if (!senderPubkey) {
+        return senderPubkey.message();
+    }
+    if (senderPubkey->second != eekId) {
+        return "The COSE_encrypt recipient does not match the expected EEK identifier";
+    }
+
+    auto sessionKey = getSessionKey(senderPubkey, eekChain, supportedEekCurve);
+    if (!sessionKey) {
+        return sessionKey.message();
+    }
+
+    auto protectedDataPayload =
+            decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
+    if (!protectedDataPayload) {
+        return protectedDataPayload.message();
+    }
+
+    auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
+    if (!parsedPayload) {
+        return "Failed to parse payload: " + payloadErrMsg;
+    }
+    if (!parsedPayload->asArray()) {
+        return "The protected data payload must be an Array.";
+    }
+    if (parsedPayload->asArray()->size() != 3U && parsedPayload->asArray()->size() != 2U) {
+        return "The protected data payload must contain SignedMAC and BCC. It may optionally "
+               "contain AdditionalDKSignatures. However, the parsed payload has " +
+               std::to_string(parsedPayload->asArray()->size()) + " entries.";
+    }
+
+    auto& signedMac = parsedPayload->asArray()->get(0);
+    auto& bcc = parsedPayload->asArray()->get(1);
+    if (!signedMac->asArray()) {
+        return "The SignedMAC in the protected data payload is not an Array.";
+    }
+    if (!bcc->asArray()) {
+        return "The BCC in the protected data payload is not an Array.";
+    }
+
+    // BCC is [ pubkey, + BccEntry]
+    auto bccContents = validateBcc(bcc->asArray());
+    if (!bccContents) {
+        return bccContents.message() + "\n" + prettyPrint(bcc.get());
+    }
+    if (bccContents->size() == 0U) {
+        return "The BCC is empty. It must contain at least one entry.";
+    }
+
+    auto deviceInfoResult =
+            parseAndValidateDeviceInfo(deviceInfo.deviceInfo, provisionable, isFactory);
+    if (!deviceInfoResult) {
+        return deviceInfoResult.message();
+    }
+    std::unique_ptr<cppbor::Map> deviceInfoMap = deviceInfoResult.moveValue();
+    auto& signingKey = bccContents->back().pubKey;
+    auto macKey = verifyAndParseCoseSign1(signedMac->asArray(), signingKey,
+                                          cppbor::Array()  // SignedMacAad
+                                                  .add(challenge)
+                                                  .add(std::move(deviceInfoMap))
+                                                  .add(keysToSignMac)
+                                                  .encode());
+    if (!macKey) {
+        return macKey.message();
+    }
+
+    auto coseMac0 = cppbor::Array()
+                            .add(cppbor::Map()  // protected
+                                         .add(ALGORITHM, HMAC_256)
+                                         .canonicalize()
+                                         .encode())
+                            .add(cppbor::Map())        // unprotected
+                            .add(keysToSign.encode())  // payload (keysToSign)
+                            .add(keysToSignMac);       // tag
+
+    auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
+    if (!macPayload) {
+        return macPayload.message();
+    }
+
+    return *bccContents;
+}
+
+ErrMsgOr<std::vector<BccEntryData>> verifyFactoryProtectedData(
+        const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
+        const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
+        const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
+        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
+    return verifyProtectedData(deviceInfo, keysToSign, keysToSignMac, protectedData, eekChain,
+                               eekId, supportedEekCurve, provisionable, challenge,
+                               /*isFactory=*/true);
+}
+
+ErrMsgOr<std::vector<BccEntryData>> verifyProductionProtectedData(
+        const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
+        const std::vector<uint8_t>& keysToSignMac, const ProtectedData& protectedData,
+        const EekChain& eekChain, const std::vector<uint8_t>& eekId, int32_t supportedEekCurve,
+        IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
+    return verifyProtectedData(deviceInfo, keysToSign, keysToSignMac, protectedData, eekChain,
+                               eekId, supportedEekCurve, provisionable, challenge,
+                               /*isFactory=*/false);
+}
+
+}  // namespace aidl::android::hardware::security::keymint::remote_prov
\ No newline at end of file
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
index f3cbd78..f2c92ae 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
@@ -351,11 +351,11 @@
                   minDelayAverageInterval / 10);
 
         // fastest rate sampling time is close to spec
-        EXPECT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs),
+        EXPECT_LE(std::abs(minDelayAverageInterval - minSamplingPeriodInNs),
                   minSamplingPeriodInNs / 10);
 
         // slowest rate sampling time is close to spec
-        EXPECT_LT(std::abs(maxDelayAverageInterval - maxSamplingPeriodInNs),
+        EXPECT_LE(std::abs(maxDelayAverageInterval - maxSamplingPeriodInNs),
                   maxSamplingPeriodInNs / 10);
     }
 
diff --git a/wifi/netlinkinterceptor/libnlinterceptor/Android.bp b/wifi/netlinkinterceptor/libnlinterceptor/Android.bp
index 00cae32..671cd85 100644
--- a/wifi/netlinkinterceptor/libnlinterceptor/Android.bp
+++ b/wifi/netlinkinterceptor/libnlinterceptor/Android.bp
@@ -37,10 +37,8 @@
         "libutils",
     ],
     sanitize: {
-        address: true,
         undefined: true,
         all_undefined: true,
-        fuzzer: true,
         cfi: true,
         integer_overflow: true,
         scs: true,