Merge changes from topic "audiocontrol_hal_2_changes"

* changes:
  Update VTS tests for AudioControl AIDL HAL version 2
  Update Default AudioControl AIDL HAL for version 2
diff --git a/audio/7.1/config/api/current.txt b/audio/7.1/config/api/current.txt
index 3a08b71..75fc5c0 100644
--- a/audio/7.1/config/api/current.txt
+++ b/audio/7.1/config/api/current.txt
@@ -359,6 +359,7 @@
     enum_constant public static final android.audio.policy.configuration.V7_1.AudioUsage AUDIO_USAGE_GAME;
     enum_constant public static final android.audio.policy.configuration.V7_1.AudioUsage AUDIO_USAGE_MEDIA;
     enum_constant public static final android.audio.policy.configuration.V7_1.AudioUsage AUDIO_USAGE_NOTIFICATION;
+    enum_constant public static final android.audio.policy.configuration.V7_1.AudioUsage AUDIO_USAGE_NOTIFICATION_EVENT;
     enum_constant public static final android.audio.policy.configuration.V7_1.AudioUsage AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
     enum_constant public static final android.audio.policy.configuration.V7_1.AudioUsage AUDIO_USAGE_SAFETY;
     enum_constant public static final android.audio.policy.configuration.V7_1.AudioUsage AUDIO_USAGE_UNKNOWN;
diff --git a/audio/7.1/config/audio_policy_configuration.xsd b/audio/7.1/config/audio_policy_configuration.xsd
index ebc23ed..7e1da90 100644
--- a/audio/7.1/config/audio_policy_configuration.xsd
+++ b/audio/7.1/config/audio_policy_configuration.xsd
@@ -443,6 +443,7 @@
             <xs:enumeration value="AUDIO_USAGE_ALARM" />
             <xs:enumeration value="AUDIO_USAGE_NOTIFICATION" />
             <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE" />
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_EVENT" />
             <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
             <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
             <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
diff --git a/audio/aidl/OWNERS b/audio/aidl/OWNERS
new file mode 100644
index 0000000..f9a2d6b
--- /dev/null
+++ b/audio/aidl/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 48436
+elaurent@google.com
+mnaganov@google.com
diff --git a/audio/common/5.0/Android.bp b/audio/common/5.0/Android.bp
index c4f3d4c..fd8e85f 100644
--- a/audio/common/5.0/Android.bp
+++ b/audio/common/5.0/Android.bp
@@ -20,4 +20,8 @@
     ],
     gen_java: true,
     gen_java_constants: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.bluetooth",
+    ],
 }
diff --git a/audio/common/all-versions/default/7.0/HidlUtils.cpp b/audio/common/all-versions/default/7.0/HidlUtils.cpp
index 218d7c0..0fd2947 100644
--- a/audio/common/all-versions/default/7.0/HidlUtils.cpp
+++ b/audio/common/all-versions/default/7.0/HidlUtils.cpp
@@ -485,8 +485,12 @@
 status_t HidlUtils::audioUsageFromHal(audio_usage_t halUsage, AudioUsage* usage) {
     if (halUsage == AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST ||
         halUsage == AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT ||
+#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
+        halUsage == AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED) {
+#else
         halUsage == AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED ||
         halUsage == AUDIO_USAGE_NOTIFICATION_EVENT) {
+#endif
         halUsage = AUDIO_USAGE_NOTIFICATION;
     }
     *usage = audio_usage_to_string(halUsage);
diff --git a/audio/common/all-versions/default/Android.bp b/audio/common/all-versions/default/Android.bp
index a25565d..9543674 100644
--- a/audio/common/all-versions/default/Android.bp
+++ b/audio/common/all-versions/default/Android.bp
@@ -211,6 +211,8 @@
     name: "android.hardware.audio.common@7.0-util_tests",
     defaults: ["android.hardware.audio.common-util_default"],
 
+    tidy_timeout_srcs: ["tests/hidlutils_tests.cpp"],
+
     srcs: ["tests/hidlutils_tests.cpp"],
 
     // Use static linking to allow running in presubmit on
@@ -241,6 +243,8 @@
     name: "android.hardware.audio.common@7.1-util_tests",
     defaults: ["android.hardware.audio.common-util_default"],
 
+    tidy_timeout_srcs: ["tests/hidlutils_tests.cpp"],
+
     srcs: ["tests/hidlutils_tests.cpp"],
 
     // Use static linking to allow running in presubmit on
diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp
index 1bd6abe..9890be2 100644
--- a/audio/common/all-versions/default/service/Android.bp
+++ b/audio/common/all-versions/default/service/Android.bp
@@ -52,6 +52,7 @@
     shared_libs: [
         "libcutils",
         "libbinder",
+        "libbinder_ndk",
         "libhidlbase",
         "liblog",
         "libutils",
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index e26369f..fbf6165 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -20,8 +20,10 @@
 #include <string>
 #include <vector>
 
+#include <android/binder_process.h>
 #include <binder/ProcessState.h>
 #include <cutils/properties.h>
+#include <dlfcn.h>
 #include <hidl/HidlTransportSupport.h>
 #include <hidl/LegacySupport.h>
 #include <hwbinder/ProcessState.h>
@@ -45,6 +47,31 @@
     return false;
 }
 
+static bool registerExternalServiceImplementation(const std::string& libName,
+                                                  const std::string& funcName) {
+    constexpr int dlMode = RTLD_LAZY;
+    void* handle = nullptr;
+    dlerror();  // clear
+    auto libPath = libName + ".so";
+    handle = dlopen(libPath.c_str(), dlMode);
+    if (handle == nullptr) {
+        const char* error = dlerror();
+        ALOGE("Failed to dlopen %s: %s", libPath.c_str(),
+              error != nullptr ? error : "unknown error");
+        return false;
+    }
+    binder_status_t (*factoryFunction)();
+    *(void**)(&factoryFunction) = dlsym(handle, funcName.c_str());
+    if (!factoryFunction) {
+        const char* error = dlerror();
+        ALOGE("Factory function %s not found in libName %s: %s", funcName.c_str(), libPath.c_str(),
+              error != nullptr ? error : "unknown error");
+        dlclose(handle);
+        return false;
+    }
+    return ((*factoryFunction)() == STATUS_OK);
+}
+
 int main(int /* argc */, char* /* argv */ []) {
     signal(SIGPIPE, SIG_IGN);
 
@@ -52,6 +79,9 @@
     // start a threadpool for vndbinder interactions
     ::android::ProcessState::self()->startThreadPool();
 
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+
     const int32_t defaultValue = -1;
     int32_t value =
         property_get_int32("persist.vendor.audio.service.hwbinder.size_kbyte", defaultValue);
@@ -101,6 +131,13 @@
             "android.hardware.bluetooth.a2dp@1.0::IBluetoothAudioOffload"
         }
     };
+
+    const std::vector<std::pair<std::string,std::string>> optionalInterfaceSharedLibs = {
+        {
+            "android.hardware.bluetooth.audio-impl",
+            "createIBluetoothAudioProviderFactory",
+        },
+    };
     // clang-format on
 
     for (const auto& listIter : mandatoryInterfaces) {
@@ -117,5 +154,15 @@
                  "Could not register %s", interfaceFamilyName.c_str());
     }
 
+    for (const auto& interfacePair : optionalInterfaceSharedLibs) {
+        const std::string& libraryName = interfacePair.first;
+        const std::string& interfaceLoaderFuncName = interfacePair.second;
+        if (registerExternalServiceImplementation(libraryName, interfaceLoaderFuncName)) {
+            ALOGI("%s() from %s success", interfaceLoaderFuncName.c_str(), libraryName.c_str());
+        } else {
+            ALOGW("%s() from %s failed", interfaceLoaderFuncName.c_str(), libraryName.c_str());
+        }
+    }
+
     joinRpcThreadpool();
 }
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index 87063a7..c757032 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -49,6 +49,9 @@
 cc_test {
     name: "VtsHalAudioV2_0TargetTest",
     defaults: ["VtsHalAudioTargetTest_defaults"],
+    tidy_timeout_srcs: [
+        "2.0/AudioPrimaryHidlHalTest.cpp",
+    ],
     srcs: [
         "2.0/AudioPrimaryHidlHalTest.cpp",
     ],
@@ -76,6 +79,9 @@
 cc_test {
     name: "VtsHalAudioV4_0TargetTest",
     defaults: ["VtsHalAudioTargetTest_defaults"],
+    tidy_timeout_srcs: [
+        "4.0/AudioPrimaryHidlHalTest.cpp",
+    ],
     srcs: [
         "4.0/AudioPrimaryHidlHalTest.cpp",
     ],
@@ -130,6 +136,9 @@
 cc_test {
     name: "VtsHalAudioV6_0TargetTest",
     defaults: ["VtsHalAudioTargetTest_defaults"],
+    tidy_timeout_srcs: [
+        "6.0/AudioPrimaryHidlHalTest.cpp",
+    ],
     srcs: [
         "6.0/AudioPrimaryHidlHalTest.cpp",
         "6.0/Generators.cpp",
@@ -158,6 +167,9 @@
 cc_test {
     name: "VtsHalAudioV7_0TargetTest",
     defaults: ["VtsHalAudioTargetTest_defaults"],
+    tidy_timeout_srcs: [
+        "7.0/AudioPrimaryHidlHalTest.cpp",
+    ],
     srcs: [
         "7.0/AudioPrimaryHidlHalTest.cpp",
         "7.0/Generators.cpp",
diff --git a/audio/effect/all-versions/vts/functional/Android.bp b/audio/effect/all-versions/vts/functional/Android.bp
index 48d6474..3b15ed4 100644
--- a/audio/effect/all-versions/vts/functional/Android.bp
+++ b/audio/effect/all-versions/vts/functional/Android.bp
@@ -26,6 +26,9 @@
 cc_defaults {
     name: "VtsHalAudioEffectTargetTest_default",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: [
+        "VtsHalAudioEffectTargetTest.cpp",
+    ],
     srcs: [
         "VtsHalAudioEffectTargetTest.cpp",
         "ValidateAudioEffectsConfiguration.cpp",
diff --git a/automotive/TEST_MAPPING b/automotive/TEST_MAPPING
new file mode 100644
index 0000000..c64c880
--- /dev/null
+++ b/automotive/TEST_MAPPING
@@ -0,0 +1,28 @@
+{
+  "auto-presubmit": [
+    {
+      "name": "AndroidCarApiTest"
+    },
+    {
+      "name": "CarSecurityPermissionTest"
+    },
+    {
+      "name": "CtsCarTestCases"
+    },
+    {
+      "name": "CtsCarBuiltinApiTestCases"
+    },
+    {
+    	"name": "CtsCarHostTestCases"
+    },
+    {
+    	"name": "CtsCarBuiltinApiHostTestCases"
+    },
+    {
+      "name": "CarServiceTest"
+    },
+    {
+      "name": "CarServiceUnitTest"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/automotive/can/1.0/default/Android.bp b/automotive/can/1.0/default/Android.bp
index 163fdb7..05691d9 100644
--- a/automotive/can/1.0/default/Android.bp
+++ b/automotive/can/1.0/default/Android.bp
@@ -46,13 +46,7 @@
     vendor: true,
     relative_install_path: "hw",
     srcs: [
-        "CanBus.cpp",
-        "CanBusNative.cpp",
-        "CanBusVirtual.cpp",
-        "CanBusSlcan.cpp",
-        "CanController.cpp",
-        "CanSocket.cpp",
-        "CloseHandle.cpp",
+        ":automotiveCanV1.0_sources",
         "service.cpp",
     ],
     shared_libs: [
@@ -66,3 +60,22 @@
     ],
     vintf_fragments: ["manifest_android.hardware.automotive.can@1.0.xml"],
 }
+
+filegroup {
+    name: "automotiveCanV1.0_sources",
+    srcs: [
+        "CanBus.cpp",
+        "CanBusNative.cpp",
+        "CanBusVirtual.cpp",
+        "CanBusSlcan.cpp",
+        "CanController.cpp",
+        "CanSocket.cpp",
+        "CloseHandle.cpp",
+    ],
+}
+
+cc_library_headers {
+    name: "automotiveCanV1.0_headers",
+    vendor: true,
+    export_include_dirs: ["."],
+}
diff --git a/automotive/can/1.0/default/libnl++/Socket.cpp b/automotive/can/1.0/default/libnl++/Socket.cpp
index cc1d839..32110fe 100644
--- a/automotive/can/1.0/default/libnl++/Socket.cpp
+++ b/automotive/can/1.0/default/libnl++/Socket.cpp
@@ -47,6 +47,17 @@
     }
 }
 
+void Socket::clearPollErr() {
+    sockaddr_nl sa = {};
+    socklen_t saLen = sizeof(sa);
+    const auto bytesReceived = recvfrom(mFd.get(), mReceiveBuffer.data(), mReceiveBuffer.size(), 0,
+                                        reinterpret_cast<sockaddr*>(&sa), &saLen);
+    if (errno != EINVAL) {
+        PLOG(WARNING) << "clearPollError() caught unexpected error: ";
+    }
+    CHECK_EQ(bytesReceived, 0) << "clearPollError() recvd " << bytesReceived << " instead of zero!";
+}
+
 bool Socket::send(const Buffer<nlmsghdr>& msg, const sockaddr_nl& sa) {
     if constexpr (kSuperVerbose) {
         LOG(VERBOSE) << (mFailed ? "(not) " : "") << "sending to " << sa.nl_pid << ": "
@@ -110,6 +121,13 @@
     if constexpr (kSuperVerbose) {
         LOG(VERBOSE) << "received from " << sa.nl_pid << ": " << toString(msg, mProtocol);
     }
+    long headerByteTotal = 0;
+    for (const auto hdr : msg) {
+        headerByteTotal += hdr->nlmsg_len;
+    }
+    if (bytesReceived != headerByteTotal) {
+        LOG(ERROR) << "received " << bytesReceived << " bytes, header claims " << headerByteTotal;
+    }
     return {msg, sa};
 }
 
@@ -159,6 +177,7 @@
 }
 
 pollfd Socket::preparePoll(short events) {
+    CHECK(mFd.get() > 0) << "Netlink socket fd is invalid!";
     return {mFd.get(), events, 0};
 }
 
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h b/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
index 7ec0f7b..996a350 100644
--- a/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
@@ -55,6 +55,12 @@
     Socket(int protocol, unsigned pid = 0, uint32_t groups = 0);
 
     /**
+     * Attempt to clear POLLERR by recv-ing.
+     * TODO(224850481): determine if this is necessary, or if the socket is locked up anyway.
+     */
+    void clearPollErr();
+
+    /**
      * Send Netlink message with incremented sequence number to the Kernel.
      *
      * \param msg Message to send. Its sequence number will be updated.
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/FamilyTracker.cpp b/automotive/can/1.0/default/libnl++/protocols/generic/FamilyTracker.cpp
index 900560e..3ad101e 100644
--- a/automotive/can/1.0/default/libnl++/protocols/generic/FamilyTracker.cpp
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/FamilyTracker.cpp
@@ -30,6 +30,7 @@
     const auto familyName = msg.attributes.get<std::string>(CTRL_ATTR_FAMILY_NAME);
     const auto familyId = msg.attributes.get<uint16_t>(CTRL_ATTR_FAMILY_ID);
 
+    // TODO(224845900): NETLINK_GENERIC == 16, and (erroneously?) sets off this warning
     if (familyId < GENL_START_ALLOC) {
         LOG(WARNING) << "Invalid family ID: " << familyId;
         return true;
diff --git a/automotive/can/1.0/default/tests/fuzzer/Android.bp b/automotive/can/1.0/default/tests/fuzzer/Android.bp
new file mode 100644
index 0000000..52b43b0
--- /dev/null
+++ b/automotive/can/1.0/default/tests/fuzzer/Android.bp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+    // 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_fuzz {
+    name: "automotiveCanV1.0_fuzzer",
+    vendor: true,
+    defaults: ["android.hardware.automotive.can@defaults"],
+    srcs: [
+        "AutomotiveCanV1_0Fuzzer.cpp",
+        ":automotiveCanV1.0_sources",
+    ],
+    header_libs: [
+        "automotiveCanV1.0_headers",
+        "android.hardware.automotive.can@hidl-utils-lib",
+    ],
+    shared_libs: [
+        "android.hardware.automotive.can@1.0",
+        "libhidlbase",
+    ],
+    static_libs: [
+        "android.hardware.automotive.can@libnetdevice",
+        "android.hardware.automotive@libc++fs",
+        "libnl++",
+    ],
+    fuzz_config: {
+        cc: [
+            "android-media-fuzzing-reports@google.com",
+        ],
+        componentid: 533764,
+    },
+}
diff --git a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp
new file mode 100644
index 0000000..96110db
--- /dev/null
+++ b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "AutomotiveCanV1_0Fuzzer.h"
+
+namespace android::hardware::automotive::can::V1_0::implementation::fuzzer {
+
+constexpr CanController::InterfaceType kInterfaceType[] = {CanController::InterfaceType::VIRTUAL,
+                                                           CanController::InterfaceType::SOCKETCAN,
+                                                           CanController::InterfaceType::SLCAN};
+constexpr FilterFlag kFilterFlag[] = {FilterFlag::DONT_CARE, FilterFlag::SET, FilterFlag::NOT_SET};
+constexpr size_t kInterfaceTypeLength = std::size(kInterfaceType);
+constexpr size_t kFilterFlagLength = std::size(kFilterFlag);
+constexpr size_t kMaxCharacters = 30;
+constexpr size_t kMaxPayloadBytes = 64;
+constexpr size_t kMaxFilters = 20;
+constexpr size_t kMaxSerialNumber = 1000;
+constexpr size_t kMaxBuses = 10;
+constexpr size_t kMaxRepeat = 5;
+
+Bus CanFuzzer::makeBus() {
+    ICanController::BusConfig config = {};
+    if (mBusNames.size() > 0 && mLastInterface < mBusNames.size()) {
+        config.name = mBusNames[mLastInterface++];
+    } else {
+        config.name = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters);
+    }
+    config.interfaceId.virtualif({mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters)});
+    return Bus(mCanController, config);
+}
+
+void CanFuzzer::getSupportedInterfaceTypes() {
+    hidl_vec<CanController::InterfaceType> iftypesResult;
+    mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&iftypesResult));
+}
+
+hidl_vec<hidl_string> CanFuzzer::getBusNames() {
+    hidl_vec<hidl_string> services = {};
+    if (auto manager = hidl::manager::V1_2::IServiceManager::getService(); manager) {
+        manager->listManifestByInterface(ICanBus::descriptor, hidl_utils::fill(&services));
+    }
+    return services;
+}
+
+void CanFuzzer::invokeUpInterface() {
+    const CanController::InterfaceType iftype =
+            kInterfaceType[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+                    0, kInterfaceTypeLength - 1)];
+    std::string configName;
+
+    if (const bool shouldInvokeValidBus = mFuzzedDataProvider->ConsumeBool();
+        (shouldInvokeValidBus) && (mBusNames.size() > 0)) {
+        const size_t busNameIndex =
+                mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, mBusNames.size() - 1);
+        configName = mBusNames[busNameIndex];
+    } else {
+        configName = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters);
+    }
+    const std::string ifname = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters);
+
+    ICanController::BusConfig config = {.name = configName};
+
+    if (iftype == CanController::InterfaceType::SOCKETCAN) {
+        CanController::BusConfig::InterfaceId::Socketcan socketcan = {};
+        if (const bool shouldPassSerialSocket = mFuzzedDataProvider->ConsumeBool();
+            shouldPassSerialSocket) {
+            socketcan.serialno(
+                    {mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kMaxSerialNumber)});
+        } else {
+            socketcan.ifname(ifname);
+        }
+        config.interfaceId.socketcan(socketcan);
+    } else if (iftype == CanController::InterfaceType::SLCAN) {
+        CanController::BusConfig::InterfaceId::Slcan slcan = {};
+        if (const bool shouldPassSerialSlcan = mFuzzedDataProvider->ConsumeBool();
+            shouldPassSerialSlcan) {
+            slcan.serialno(
+                    {mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kMaxSerialNumber)});
+        } else {
+            slcan.ttyname(ifname);
+        }
+        config.interfaceId.slcan(slcan);
+    } else if (iftype == CanController::InterfaceType::VIRTUAL) {
+        config.interfaceId.virtualif({ifname});
+    }
+
+    const size_t numInvocations =
+            mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, kMaxRepeat);
+    for (size_t i = 0; i < numInvocations; ++i) {
+        mCanController->upInterface(config);
+    }
+}
+
+void CanFuzzer::invokeDownInterface() {
+    hidl_string configName;
+    if (const bool shouldInvokeValidBus = mFuzzedDataProvider->ConsumeBool();
+        (shouldInvokeValidBus) && (mBusNames.size() > 0)) {
+        const size_t busNameIndex =
+                mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, mBusNames.size() - 1);
+        configName = mBusNames[busNameIndex];
+    } else {
+        configName = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters);
+    }
+
+    const size_t numInvocations =
+            mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, kMaxRepeat);
+    for (size_t i = 0; i < numInvocations; ++i) {
+        mCanController->downInterface(configName);
+    }
+}
+
+void CanFuzzer::invokeController() {
+    getSupportedInterfaceTypes();
+    invokeUpInterface();
+    invokeDownInterface();
+}
+
+void CanFuzzer::invokeBus() {
+    const size_t numBuses = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(1, kMaxBuses);
+    for (size_t i = 0; i < numBuses; ++i) {
+        if (const bool shouldSendMessage = mFuzzedDataProvider->ConsumeBool(); shouldSendMessage) {
+            auto sendingBus = makeBus();
+            CanMessage msg = {.id = mFuzzedDataProvider->ConsumeIntegral<uint32_t>()};
+            uint32_t numPayloadBytes =
+                    mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kMaxPayloadBytes);
+            hidl_vec<uint8_t> payload(numPayloadBytes);
+            for (uint32_t j = 0; j < numPayloadBytes; ++j) {
+                payload[j] = mFuzzedDataProvider->ConsumeIntegral<uint32_t>();
+            }
+            msg.payload = payload;
+            msg.remoteTransmissionRequest = mFuzzedDataProvider->ConsumeBool();
+            msg.isExtendedId = mFuzzedDataProvider->ConsumeBool();
+            sendingBus.send(msg);
+        } else {
+            auto listeningBus = makeBus();
+            uint32_t numFilters =
+                    mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(1, kMaxFilters);
+            hidl_vec<CanMessageFilter> filterVector(numFilters);
+            for (uint32_t k = 0; k < numFilters; ++k) {
+                filterVector[k].id = mFuzzedDataProvider->ConsumeIntegral<uint32_t>();
+                filterVector[k].mask = mFuzzedDataProvider->ConsumeIntegral<uint32_t>();
+                filterVector[k].rtr =
+                        kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+                                0, kFilterFlagLength - 1)];
+                filterVector[k].extendedFormat =
+                        kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+                                0, kFilterFlagLength - 1)];
+                filterVector[k].exclude = mFuzzedDataProvider->ConsumeBool();
+            }
+            auto listener = listeningBus.listen(filterVector);
+        }
+    }
+}
+
+void CanFuzzer::deInit() {
+    mCanController.clear();
+    if (mFuzzedDataProvider) {
+        delete mFuzzedDataProvider;
+    }
+    mBusNames = {};
+}
+
+void CanFuzzer::process(const uint8_t* data, size_t size) {
+    mFuzzedDataProvider = new FuzzedDataProvider(data, size);
+    invokeController();
+    invokeBus();
+}
+
+bool CanFuzzer::init() {
+    mCanController = sp<CanController>::make();
+    if (!mCanController) {
+        return false;
+    }
+    mBusNames = getBusNames();
+    return true;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    if (size < 1) {
+        return 0;
+    }
+    CanFuzzer canFuzzer;
+    if (canFuzzer.init()) {
+        canFuzzer.process(data, size);
+    }
+    return 0;
+}
+
+}  // namespace android::hardware::automotive::can::V1_0::implementation::fuzzer
diff --git a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h
new file mode 100644
index 0000000..930cddd
--- /dev/null
+++ b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __AUTOMOTIVE_CAN_V1_0_FUZZER_H__
+#define __AUTOMOTIVE_CAN_V1_0_FUZZER_H__
+#include <CanController.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <hidl-utils/hidl-utils.h>
+
+namespace android::hardware::automotive::can::V1_0::implementation::fuzzer {
+
+using ::android::sp;
+
+struct CanMessageListener : public can::V1_0::ICanMessageListener {
+    DISALLOW_COPY_AND_ASSIGN(CanMessageListener);
+
+    CanMessageListener() {}
+
+    virtual Return<void> onReceive(const can::V1_0::CanMessage& msg) override {
+        std::unique_lock<std::mutex> lock(mMessagesGuard);
+        mMessages.push_back(msg);
+        mMessagesUpdated.notify_one();
+        return {};
+    }
+
+    virtual ~CanMessageListener() {
+        if (mCloseHandle) {
+            mCloseHandle->close();
+        }
+    }
+
+    void assignCloseHandle(sp<ICloseHandle> closeHandle) { mCloseHandle = closeHandle; }
+
+  private:
+    sp<ICloseHandle> mCloseHandle;
+
+    std::mutex mMessagesGuard;
+    std::condition_variable mMessagesUpdated GUARDED_BY(mMessagesGuard);
+    std::vector<can::V1_0::CanMessage> mMessages GUARDED_BY(mMessagesGuard);
+};
+
+struct Bus {
+    DISALLOW_COPY_AND_ASSIGN(Bus);
+
+    Bus(sp<ICanController> controller, const ICanController::BusConfig& config)
+        : mIfname(config.name), mController(controller) {
+        const auto result = controller->upInterface(config);
+        const auto manager = hidl::manager::V1_2::IServiceManager::getService();
+        const auto service = manager->get(ICanBus::descriptor, config.name);
+        mBus = ICanBus::castFrom(service);
+    }
+
+    virtual ~Bus() { reset(); }
+
+    void reset() {
+        mBus.clear();
+        if (mController) {
+            mController->downInterface(mIfname);
+            mController.clear();
+        }
+    }
+
+    ICanBus* operator->() const { return mBus.get(); }
+    sp<ICanBus> get() { return mBus; }
+
+    sp<CanMessageListener> listen(const hidl_vec<CanMessageFilter>& filter) {
+        sp<CanMessageListener> listener = sp<CanMessageListener>::make();
+
+        if (!mBus) {
+            return listener;
+        }
+        Result result;
+        sp<ICloseHandle> closeHandle;
+        mBus->listen(filter, listener, hidl_utils::fill(&result, &closeHandle)).assertOk();
+        listener->assignCloseHandle(closeHandle);
+
+        return listener;
+    }
+
+    void send(const CanMessage& msg) {
+        if (!mBus) {
+            return;
+        }
+        mBus->send(msg);
+    }
+
+  private:
+    const std::string mIfname;
+    sp<ICanController> mController;
+    sp<ICanBus> mBus;
+};
+
+class CanFuzzer {
+  public:
+    ~CanFuzzer() { deInit(); }
+    bool init();
+    void process(const uint8_t* data, size_t size);
+    void deInit();
+
+  private:
+    Bus makeBus();
+    hidl_vec<hidl_string> getBusNames();
+    void getSupportedInterfaceTypes();
+    void invokeBus();
+    void invokeController();
+    void invokeUpInterface();
+    void invokeDownInterface();
+    FuzzedDataProvider* mFuzzedDataProvider = nullptr;
+    sp<CanController> mCanController = nullptr;
+    hidl_vec<hidl_string> mBusNames = {};
+    unsigned mLastInterface = 0;
+};
+}  // namespace android::hardware::automotive::can::V1_0::implementation::fuzzer
+
+#endif  // __AUTOMOTIVE_CAN_V1_0_FUZZER_H__
diff --git a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
index ad607d8..9c72acd 100644
--- a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
+++ b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
@@ -18,7 +18,7 @@
 
 
 // These values are called out in the EVS design doc (as of Mar 8, 2017)
-static const int kMaxStreamStartMilliseconds = 500;
+static const int kMaxStreamStartMilliseconds = 1000;
 static const int kMinimumFramesPerSecond = 10;
 
 static const int kSecondsToMilliseconds = 1000;
@@ -332,11 +332,6 @@
         printf("Measured time to first frame %0.2f ms\n", timeToFirstFrame * kNanoToMilliseconds);
         ALOGI("Measured time to first frame %0.2f ms", timeToFirstFrame * kNanoToMilliseconds);
 
-        // Check aspect ratio
-        unsigned width = 0, height = 0;
-        frameHandler->getFrameDimension(&width, &height);
-        EXPECT_GE(width, height);
-
         // Wait a bit, then ensure we get at least the required minimum number of frames
         sleep(5);
         nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -370,7 +365,7 @@
     ALOGI("Starting CameraStreamBuffering test");
 
     // Arbitrary constant (should be > 1 and not too big)
-    static const unsigned int kBuffersToHold = 6;
+    static const unsigned int kBuffersToHold = 2;
 
     // Get the camera list
     loadCameraList();
diff --git a/automotive/evs/1.1/vts/functional/Android.bp b/automotive/evs/1.1/vts/functional/Android.bp
index cbc2150..18687bf 100644
--- a/automotive/evs/1.1/vts/functional/Android.bp
+++ b/automotive/evs/1.1/vts/functional/Android.bp
@@ -25,6 +25,9 @@
 
 cc_test {
     name: "VtsHalEvsV1_1TargetTest",
+    tidy_timeout_srcs: [
+        "VtsHalEvsV1_1TargetTest.cpp",
+    ],
     srcs: [
         "FrameHandler.cpp",
         "FrameHandlerUltrasonics.cpp",
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index c33a2e7..84323ea 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -499,11 +499,6 @@
                   << std::scientific << timeToFirstFrame * kNanoToMilliseconds
                   << " ms.";
 
-        // Check aspect ratio
-        unsigned width = 0, height = 0;
-        frameHandler->getFrameDimension(&width, &height);
-        EXPECT_GE(width, height);
-
         // Wait a bit, then ensure we get at least the required minimum number of frames
         sleep(5);
         nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -541,7 +536,7 @@
     LOG(INFO) << "Starting CameraStreamBuffering test";
 
     // Arbitrary constant (should be > 1 and not too big)
-    static const unsigned int kBuffersToHold = 6;
+    static const unsigned int kBuffersToHold = 2;
 
     // Get the camera list
     loadCameraList();
diff --git a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Stream.aidl b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Stream.aidl
index a780412..154a693 100644
--- a/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Stream.aidl
+++ b/automotive/evs/aidl/aidl_api/android.hardware.automotive.evs/current/android/hardware/automotive/evs/Stream.aidl
@@ -38,6 +38,7 @@
   android.hardware.automotive.evs.StreamType streamType;
   int width;
   int height;
+  int framerate;
   android.hardware.graphics.common.PixelFormat format;
   android.hardware.graphics.common.BufferUsage usage;
   android.hardware.automotive.evs.Rotation rotation;
diff --git a/automotive/evs/aidl/android/hardware/automotive/evs/Stream.aidl b/automotive/evs/aidl/android/hardware/automotive/evs/Stream.aidl
index ae5c7f0..663ba22 100644
--- a/automotive/evs/aidl/android/hardware/automotive/evs/Stream.aidl
+++ b/automotive/evs/aidl/android/hardware/automotive/evs/Stream.aidl
@@ -55,7 +55,7 @@
     int height;
     /**
      * The frame rate of this stream in frames-per-second
-     /
+     */
     int framerate;
     /**
      * The pixel format form the buffers in this stream.
diff --git a/automotive/sv/1.0/vts/functional/Android.bp b/automotive/sv/1.0/vts/functional/Android.bp
index 1ff3450..e94893c 100644
--- a/automotive/sv/1.0/vts/functional/Android.bp
+++ b/automotive/sv/1.0/vts/functional/Android.bp
@@ -25,6 +25,9 @@
 
 cc_test {
     name: "VtsHalSurroundViewV1_0TargetTest",
+    tidy_timeout_srcs: [
+        "VtsHalSurroundViewV1_0TargetTest.cpp",
+    ],
     srcs: [
         "VtsHalSurroundViewV1_0TargetTest.cpp",
         "SurroundViewStreamHandler.cpp",
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 3cf41dc..0d3253b 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -162,6 +162,9 @@
     vendor: true,
     defaults: ["vhal_v2_0_target_defaults"],
     whole_static_libs: ["android.hardware.automotive.vehicle@2.0-manager-lib"],
+    tidy_timeout_srcs: [
+        "tests/VmsUtils_test.cpp",
+    ],
     srcs: [
         "tests/RecurrentTimer_test.cpp",
         "tests/SubscriptionManager_test.cpp",
diff --git a/automotive/vehicle/2.0/utils/Android.bp b/automotive/vehicle/2.0/utils/Android.bp
index a75ce49..770d447 100644
--- a/automotive/vehicle/2.0/utils/Android.bp
+++ b/automotive/vehicle/2.0/utils/Android.bp
@@ -39,6 +39,9 @@
     name: "android.hardware.automotive.vehicle@2.0-utils-unit-tests",
     defaults: ["vhal_v2_0_defaults"],
     vendor: true,
+    tidy_timeout_srcs: [
+        "tests/UserHalHelper_test.cpp",
+    ],
     srcs: [
         "tests/UserHalHelper_test.cpp",
     ],
diff --git a/automotive/vehicle/2.0/vts/functional/Android.bp b/automotive/vehicle/2.0/vts/functional/Android.bp
deleted file mode 100644
index e64e942..0000000
--- a/automotive/vehicle/2.0/vts/functional/Android.bp
+++ /dev/null
@@ -1,30 +0,0 @@
-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_test {
-    name: "VtsHalAutomotiveVehicleV2_0TargetTest",
-    defaults: [
-        "VtsHalTargetTestDefaults",
-    ],
-    srcs: [
-        "VtsHalAutomotiveVehicleV2_0TargetTest.cpp",
-    ],
-    shared_libs: [
-        "libbase",
-        "libhidlbase",
-        "liblog",
-    ],
-    static_libs: [
-        "android.hardware.automotive.vehicle@2.0",
-    ],
-    test_suites: [
-        "vts",
-        "general-tests",
-    ],
-}
diff --git a/automotive/vehicle/2.0/vts/functional/VtsHalAutomotiveVehicleV2_0TargetTest.cpp b/automotive/vehicle/2.0/vts/functional/VtsHalAutomotiveVehicleV2_0TargetTest.cpp
deleted file mode 100644
index 8adec84..0000000
--- a/automotive/vehicle/2.0/vts/functional/VtsHalAutomotiveVehicleV2_0TargetTest.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "VtsHalAutomotiveVehicle"
-
-#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
-#include <utils/Log.h>
-#include <unordered_set>
-
-#include <gtest/gtest.h>
-#include <hidl/GtestPrinter.h>
-#include <hidl/ServiceManagement.h>
-
-using namespace android::hardware::automotive::vehicle::V2_0;
-using ::android::sp;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-
-constexpr auto kTimeout = std::chrono::milliseconds(500);
-constexpr auto kInvalidProp = 0x31600207;
-
-class VtsVehicleCallback : public IVehicleCallback {
-  private:
-    using MutexGuard = std::lock_guard<std::mutex>;
-    using HidlVecOfValues = hidl_vec<VehiclePropValue>;
-    std::mutex mLock;
-    std::condition_variable mEventCond;
-    std::vector<HidlVecOfValues> mReceivedEvents;
-
-  public:
-    Return<void> onPropertyEvent(const hidl_vec<VehiclePropValue>& values) override {
-        {
-            MutexGuard guard(mLock);
-            mReceivedEvents.push_back(values);
-        }
-        mEventCond.notify_one();
-        return Return<void>();
-    }
-
-    Return<void> onPropertySet(const VehiclePropValue& /* value */) override {
-        return Return<void>();
-    }
-    Return<void> onPropertySetError(StatusCode /* errorCode */, int32_t /* propId */,
-                                    int32_t /* areaId */) override {
-        return Return<void>();
-    }
-
-    bool waitForExpectedEvents(size_t expectedEvents) {
-        std::unique_lock<std::mutex> g(mLock);
-
-        if (expectedEvents == 0 && mReceivedEvents.size() == 0) {
-            return mEventCond.wait_for(g, kTimeout) == std::cv_status::timeout;
-        }
-
-        while (expectedEvents != mReceivedEvents.size()) {
-            if (mEventCond.wait_for(g, kTimeout) == std::cv_status::timeout) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    void reset() { mReceivedEvents.clear(); }
-};
-
-class VehicleHalHidlTest : public testing::TestWithParam<std::string> {
-  public:
-    virtual void SetUp() override {
-        mVehicle = IVehicle::getService(GetParam());
-        ASSERT_NE(mVehicle.get(), nullptr);
-    }
-    virtual void TearDown() override {}
-
-    sp<IVehicle> mVehicle;
-
-    bool isBooleanGlobalProp(int32_t property) {
-        return (property & (int)VehiclePropertyType::MASK) == (int)VehiclePropertyType::BOOLEAN &&
-               (property & (int)VehicleArea::MASK) == (int)VehicleArea::GLOBAL;
-    }
-
-    void invokeGet(int32_t property, int32_t areaId) {
-        VehiclePropValue requestedValue{};
-        requestedValue.prop = property;
-        requestedValue.areaId = areaId;
-
-        invokeGet(requestedValue);
-    }
-
-    void invokeGet(const VehiclePropValue& requestedPropValue) {
-        mActualValue = VehiclePropValue{};  // reset previous values
-
-        StatusCode refStatus;
-        VehiclePropValue refValue;
-        bool isCalled = false;
-        mVehicle->get(requestedPropValue,
-                      [&refStatus, &refValue, &isCalled](StatusCode status,
-                                                         const VehiclePropValue& value) {
-                          refStatus = status;
-                          refValue = value;
-                          isCalled = true;
-                      });
-        ASSERT_TRUE(isCalled) << "callback wasn't called for property: " << requestedPropValue.prop;
-
-        mActualValue = refValue;
-        mActualStatusCode = refStatus;
-    }
-
-    VehiclePropValue mActualValue;
-    StatusCode mActualStatusCode;
-};
-
-// Test getAllPropConfig() returns at least 4 property configs.
-TEST_P(VehicleHalHidlTest, getAllPropConfigs) {
-    ALOGD("VehicleHalHidlTest::getAllPropConfigs");
-    bool isCalled = false;
-    hidl_vec<VehiclePropConfig> propConfigs;
-    mVehicle->getAllPropConfigs([&isCalled, &propConfigs](const hidl_vec<VehiclePropConfig>& cfgs) {
-        propConfigs = cfgs;
-        isCalled = true;
-    });
-    ASSERT_TRUE(isCalled);
-    ASSERT_GE(propConfigs.size(), 4);
-}
-
-// Test getPropConfig() can query all properties listed in CDD.
-TEST_P(VehicleHalHidlTest, getPropConfigs) {
-    ALOGD("VehicleHalHidlTest::getPropConfigs");
-    // Check the properties listed in CDD
-    hidl_vec<int32_t> properties = {
-            (int)VehicleProperty::GEAR_SELECTION, (int)VehicleProperty::NIGHT_MODE,
-            (int)VehicleProperty::PARKING_BRAKE_ON, (int)VehicleProperty::PERF_VEHICLE_SPEED};
-    bool isCalled = false;
-    mVehicle->getPropConfigs(
-            properties, [&isCalled](StatusCode status, const hidl_vec<VehiclePropConfig>& cfgs) {
-                ASSERT_EQ(StatusCode::OK, status);
-                ASSERT_EQ(4u, cfgs.size());
-                isCalled = true;
-            });
-    ASSERT_TRUE(isCalled);
-}
-
-// Test getPropConfig() with an invalid propertyId returns an error code.
-TEST_P(VehicleHalHidlTest, getPropConfigsWithInvalidProp) {
-    ALOGD("VehicleHalHidlTest::getPropConfigsWithInvalidProp");
-    hidl_vec<int32_t> properties = {kInvalidProp};
-    bool isCalled = false;
-    mVehicle->getPropConfigs(
-            properties, [&isCalled](StatusCode status, const hidl_vec<VehiclePropConfig>& cfgs) {
-                ASSERT_NE(StatusCode::OK, status);
-                ASSERT_EQ(0, cfgs.size());
-                isCalled = true;
-            });
-    ASSERT_TRUE(isCalled);
-}
-
-// Test get() return current value for properties.
-TEST_P(VehicleHalHidlTest, get) {
-    ALOGD("VehicleHalHidlTest::get");
-    invokeGet((int)VehicleProperty::PERF_VEHICLE_SPEED, 0);
-    ASSERT_EQ(StatusCode::OK, mActualStatusCode);
-}
-
-// Test get() with an invalid propertyId return an error codes.
-TEST_P(VehicleHalHidlTest, getInvalidProp) {
-    ALOGD("VehicleHalHidlTest::getInvalidProp");
-
-    invokeGet(kInvalidProp, 0);
-    ASSERT_NE(StatusCode::OK, mActualStatusCode);
-}
-
-// Test set() on read_write properties.
-TEST_P(VehicleHalHidlTest, setProp) {
-    ALOGD("VehicleHalHidlTest::setProp");
-    hidl_vec<VehiclePropConfig> propConfigs;
-    // skip hvac related properties
-    std::unordered_set<int32_t> hvacProps = {(int)VehicleProperty::HVAC_DEFROSTER,
-                                             (int)VehicleProperty::HVAC_AC_ON,
-                                             (int)VehicleProperty::HVAC_MAX_AC_ON,
-                                             (int)VehicleProperty::HVAC_MAX_DEFROST_ON,
-                                             (int)VehicleProperty::HVAC_RECIRC_ON,
-                                             (int)VehicleProperty::HVAC_DUAL_ON,
-                                             (int)VehicleProperty::HVAC_AUTO_ON,
-                                             (int)VehicleProperty::HVAC_POWER_ON,
-                                             (int)VehicleProperty::HVAC_AUTO_RECIRC_ON,
-                                             (int)VehicleProperty::HVAC_ELECTRIC_DEFROSTER_ON};
-    mVehicle->getAllPropConfigs(
-            [&propConfigs](const hidl_vec<VehiclePropConfig>& cfgs) { propConfigs = cfgs; });
-    for (const VehiclePropConfig& cfg : propConfigs) {
-        // test on boolean and writable property
-        if (cfg.access == VehiclePropertyAccess::READ_WRITE && isBooleanGlobalProp(cfg.prop) &&
-            !hvacProps.count(cfg.prop)) {
-            invokeGet(cfg.prop, 0);
-            int setValue = mActualValue.value.int32Values[0] == 1 ? 0 : 1;
-            VehiclePropValue propToSet = mActualValue;
-            propToSet.value.int32Values[0] = setValue;
-            ASSERT_EQ(StatusCode::OK, mVehicle->set(propToSet))
-                    << "Invalid status code for setting property: " << cfg.prop;
-            // check set success
-            invokeGet(cfg.prop, 0);
-            ASSERT_EQ(StatusCode::OK, mActualStatusCode);
-            ASSERT_EQ(setValue, mActualValue.value.int32Values[0])
-                    << "Failed to set value for property: " << cfg.prop;
-        }
-    }
-}
-
-// Test set() on an read_only property.
-TEST_P(VehicleHalHidlTest, setNotWritableProp) {
-    ALOGD("VehicleHalHidlTest::setNotWritableProp");
-    invokeGet(static_cast<int>(VehicleProperty::PERF_VEHICLE_SPEED), 0);
-    ASSERT_EQ(StatusCode::OK, mActualStatusCode);
-    VehiclePropValue vehicleSpeed = mActualValue;
-
-    ASSERT_EQ(StatusCode::ACCESS_DENIED, mVehicle->set(vehicleSpeed));
-}
-
-// Test subscribe() and unsubscribe().
-TEST_P(VehicleHalHidlTest, subscribeAndUnsubscribe) {
-    ALOGD("VehicleHalHidlTest::subscribeAndUnsubscribe");
-    const auto prop = static_cast<int>(VehicleProperty::PERF_VEHICLE_SPEED);
-    sp<VtsVehicleCallback> cb = new VtsVehicleCallback();
-
-    hidl_vec<SubscribeOptions> options = {
-            SubscribeOptions{.propId = prop, 100.0, .flags = SubscribeFlags::EVENTS_FROM_CAR}};
-
-    ASSERT_EQ(StatusCode::OK, mVehicle->subscribe(cb, options));
-    ASSERT_TRUE(cb->waitForExpectedEvents(10));
-
-    ASSERT_EQ(StatusCode::OK, mVehicle->unsubscribe(cb, prop));
-    cb->reset();
-    ASSERT_FALSE(cb->waitForExpectedEvents(10));
-}
-
-// Test subscribe() with an invalid property.
-TEST_P(VehicleHalHidlTest, subscribeInvalidProp) {
-    ALOGD("VehicleHalHidlTest::subscribeInvalidProp");
-
-    sp<VtsVehicleCallback> cb = new VtsVehicleCallback();
-
-    hidl_vec<SubscribeOptions> options = {SubscribeOptions{
-            .propId = kInvalidProp, 10.0, .flags = SubscribeFlags::EVENTS_FROM_CAR}};
-
-    ASSERT_NE(StatusCode::OK, mVehicle->subscribe(cb, options));
-}
-
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VehicleHalHidlTest);
-INSTANTIATE_TEST_SUITE_P(
-        PerInstance, VehicleHalHidlTest,
-        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVehicle::descriptor)),
-        android::hardware::PrintInstanceNameToString);
diff --git a/automotive/vehicle/TEST_MAPPING b/automotive/vehicle/TEST_MAPPING
index ff6f3be..7e42554 100644
--- a/automotive/vehicle/TEST_MAPPING
+++ b/automotive/vehicle/TEST_MAPPING
@@ -24,5 +24,10 @@
     {
       "name": "DefaultVehicleHalTest"
     }
+  ],
+  "auto-presubmit": [
+    {
+      "name": "VtsHalAutomotiveVehicle_TargetTest"
+    }
   ]
 }
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/CustomInputType.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/CustomInputType.aidl
index 10dbfd0..0f4855e 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/CustomInputType.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/CustomInputType.aidl
@@ -23,10 +23,11 @@
 @Backing(type="int")
 enum CustomInputType {
     /**
-     * Ten functions representing the custom input code to be defined and implemented by OEM
-     * partners.
+     * Ten optional functions to be used in case OEM don't need more than 10 input code values.
      *
-     * OEMs need to formally contact Android team if more than 10 functions are required.
+     * OEMs are free to use any signed 32 bits number to represent the input code value.
+     * The following function keys are only for convenience and any other integer values are
+     * also allowed.
      */
     CUSTOM_EVENT_F1 = 1001,
     CUSTOM_EVENT_F2 = 1002,
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
index a947963..dc9b876 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
@@ -165,6 +165,11 @@
      *    a property set failure message sent from the vehicle bus.
      * @param options List of options to subscribe. SubscribeOption contains
      *    information such as property Id, area Id, sample rate, etc.
+     *    For continuous properties, sample rate must be provided. If sample
+     *    rate is less than {@link VehiclePropConfig#minSampleRate}, the sample
+     *    rate would be minSampleRate. If sample rate is larger than
+     *    {@link VehiclePropValue#maxSampleRate}, the sample rate would be
+     *    maxSampleRate.
      * @param maxSharedMemoryFileCount The maximum number of shared memory files
      *    allocated for in VHAL for this subscription. When a memory file is
      *    handled back to the client, it cannot be used by VHAL to deliver
diff --git a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h b/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
index d2b69af..6ecac70 100644
--- a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
+++ b/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
@@ -754,8 +754,7 @@
         {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
                     .access = VehiclePropertyAccess::READ,
                     .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                    .configArray = {3}},
-         .initialValue = {.int32Values = {toInt(VehicleApPowerStateReq::ON), 0}}},
+                    .configArray = {3}}},
 
         {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
                     .access = VehiclePropertyAccess::READ_WRITE,
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/JsonFakeValueGenerator.h b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/JsonFakeValueGenerator.h
index 947eb4f..d421ac5 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/JsonFakeValueGenerator.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/include/JsonFakeValueGenerator.h
@@ -56,7 +56,7 @@
   private:
     size_t mEventIndex = 0;
     std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue> mEvents;
-    long mLastEventTimestamp = 0;
+    int64_t mLastEventTimestamp = 0;
     int32_t mNumOfIterations = 0;
 
     void setBit(std::vector<uint8_t>& bytes, size_t idx);
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/JsonFakeValueGenerator.cpp b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/JsonFakeValueGenerator.cpp
index ae92797..d4d52a5 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/JsonFakeValueGenerator.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/src/JsonFakeValueGenerator.cpp
@@ -213,7 +213,7 @@
     if (mLastEventTimestamp == 0) {
         mLastEventTimestamp = elapsedRealtimeNano();
     } else {
-        long nextEventTime = 0;
+        int64_t nextEventTime = 0;
         if (mEventIndex > 0) {
             // All events (start from 2nd one) are supposed to happen in the future with a delay
             // equals to the duration between previous and current event.
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp
index ac8db44..2eef13c 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp
@@ -41,6 +41,7 @@
     name: "FakeVehicleHalValueGeneratorsTestFiles",
     srcs: [
         "prop.json",
+        "prop_different_types.json",
         "prop_invalid.json",
     ],
 }
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/FakeVehicleHalValueGeneratorsTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/FakeVehicleHalValueGeneratorsTest.cpp
index 21aa680..cdfa8b2 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/FakeVehicleHalValueGeneratorsTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/FakeVehicleHalValueGeneratorsTest.cpp
@@ -24,6 +24,7 @@
 #include <utils/SystemClock.h>
 
 #include <chrono>
+#include <condition_variable>
 #include <memory>
 #include <mutex>
 #include <optional>
@@ -38,6 +39,9 @@
 
 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::android::base::ScopedLockAssertion;
+
+using std::literals::chrono_literals::operator""s;
 
 class FakeVehicleHalValueGeneratorsTest : public ::testing::Test {
   protected:
@@ -58,6 +62,16 @@
         mEvents.clear();
     }
 
+    void waitForEvents(size_t count) {
+        std::unique_lock<std::mutex> uniqueLock(mEventsLock);
+        bool result = mCv.wait_for(uniqueLock, 10s, [this, count] {
+            ScopedLockAssertion lockAssertion(mEventsLock);
+            return mEvents.size() >= count;
+        });
+
+        ASSERT_TRUE(result) << "didn't receive enough events";
+    }
+
     void TearDown() override {
         // Generator callback uses mEvents, must stop generator before destroying mEvents.
         mHub.reset();
@@ -71,12 +85,16 @@
   private:
     void onHalEvent(const VehiclePropValue& event) {
         VehiclePropValue eventCopy = event;
-        std::scoped_lock<std::mutex> lockGuard(mEventsLock);
-        mEvents.push_back(std::move(eventCopy));
+        {
+            std::scoped_lock<std::mutex> lockGuard(mEventsLock);
+            mEvents.push_back(std::move(eventCopy));
+        }
+        mCv.notify_all();
     }
 
     std::unique_ptr<GeneratorHub> mHub;
     std::mutex mEventsLock;
+    std::condition_variable mCv;
     std::vector<VehiclePropValue> mEvents GUARDED_BY(mEventsLock);
 };
 
@@ -108,15 +126,15 @@
     for (size_t i = 0; i < eventCount; i++) {
         events.push_back(VehiclePropValue{
                 .prop = static_cast<int32_t>(i),
-                .timestamp = timestamp + static_cast<int64_t>(50 * i),
+                // Generate 1 event every 1ms.
+                .timestamp = timestamp + static_cast<int64_t>(1000000 * i),
         });
     }
     generator->setEvents(events);
 
     getHub()->registerGenerator(0, std::move(generator));
 
-    // All the events require 500ms to generate, so waiting for 1000ms should be enough.
-    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+    waitForEvents(events.size());
 
     ASSERT_EQ(getEvents(), events);
 
@@ -131,17 +149,23 @@
     for (size_t i = 0; i < eventCount; i++) {
         events.push_back(VehiclePropValue{
                 .prop = static_cast<int32_t>(i),
-                .timestamp = timestamp + static_cast<int64_t>(50 * i),
+                // Generate 1 event every 1ms.
+                .timestamp = timestamp + static_cast<int64_t>(1000000 * i),
         });
     }
     generator->setEvents(events);
 
     getHub()->registerGenerator(0, std::move(generator));
+
+    waitForEvents(1);
+
     getHub()->unregisterGenerator(0);
+    clearEvents();
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+    std::this_thread::sleep_for(std::chrono::milliseconds(100));
 
-    ASSERT_LT(getEvents().size(), static_cast<size_t>(10))
+    // It is possible that one last event would be generated after unregistering.
+    ASSERT_LE(getEvents().size(), 1u)
             << "Must stop generating event after generator is unregistered";
 }
 
@@ -155,13 +179,11 @@
                                                        /*interval=*/10000000);
     getHub()->registerGenerator(0, std::move(generator));
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-
+    waitForEvents(10);
     auto events = getEvents();
-    // We should get 10 events ideally, but let's be safe here.
-    ASSERT_LE((size_t)5, events.size());
+
     int value = 30;
-    for (size_t i = 0; i < 5; i++) {
+    for (size_t i = 0; i < 10; i++) {
         EXPECT_EQ(std::vector<float>({static_cast<float>(value)}), events[i].value.floatValues);
         value = (value + 20) % 100;
     }
@@ -177,13 +199,11 @@
                                                        /*interval=*/10000000);
     getHub()->registerGenerator(0, std::move(generator));
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-
+    waitForEvents(10);
     auto events = getEvents();
-    // We should get 10 events ideally, but let's be safe here.
-    ASSERT_LE((size_t)5, events.size());
+
     int value = 30;
-    for (size_t i = 0; i < 5; i++) {
+    for (size_t i = 0; i < 10; i++) {
         EXPECT_EQ(std::vector<int32_t>({value}), events[i].value.int32Values);
         value = (value + 20) % 100;
     }
@@ -199,13 +219,11 @@
                                                        /*interval=*/10000000);
     getHub()->registerGenerator(0, std::move(generator));
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-
+    waitForEvents(10);
     auto events = getEvents();
-    // We should get 10 events ideally, but let's be safe here.
-    ASSERT_LE((size_t)5, events.size());
+
     int value = 30;
-    for (size_t i = 0; i < 5; i++) {
+    for (size_t i = 0; i < 10; i++) {
         EXPECT_EQ(std::vector<int64_t>({value}), events[i].value.int64Values);
         value = (value + 20) % 100;
     }
@@ -221,13 +239,11 @@
             std::make_unique<LinearFakeValueGenerator>(request);
     getHub()->registerGenerator(0, std::move(generator));
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-
+    waitForEvents(10);
     auto events = getEvents();
-    // We should get 10 events ideally, but let's be safe here.
-    ASSERT_LE((size_t)5, events.size());
+
     int value = 50;
-    for (size_t i = 0; i < 5; i++) {
+    for (size_t i = 0; i < 10; i++) {
         EXPECT_EQ(std::vector<float>({static_cast<float>(value)}), events[i].value.floatValues);
         value = (value + 20) % 100;
     }
@@ -244,30 +260,24 @@
                                                        /*interval=*/10000000);
     getHub()->registerGenerator(0, std::move(generator));
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-
+    waitForEvents(10);
     auto events = getEvents();
-    // We should get 10 events ideally, but let's be safe here.
-    ASSERT_LE((size_t)5, events.size());
 
     // Init value would be set to middleValue if given initValue is not valid.
     int value = 50;
-    for (size_t i = 0; i < 5; i++) {
+    for (size_t i = 0; i < 10; i++) {
         EXPECT_EQ(std::vector<float>({static_cast<float>(value)}), events[i].value.floatValues);
         value = (value + 20) % 100;
     }
 }
 
 TEST_F(FakeVehicleHalValueGeneratorsTest, testJsonFakeValueGenerator) {
-    long currentTime = elapsedRealtimeNano();
+    int64_t currentTime = elapsedRealtimeNano();
 
     std::unique_ptr<JsonFakeValueGenerator> generator =
             std::make_unique<JsonFakeValueGenerator>(getTestFilePath("prop.json"), 2);
     getHub()->registerGenerator(0, std::move(generator));
 
-    // wait for some time.
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-
     std::vector<VehiclePropValue> expectedValues = {
             VehiclePropValue{
                     .areaId = 0,
@@ -296,9 +306,10 @@
         expectedValues.push_back(expectedValues[i]);
     }
 
+    waitForEvents(expectedValues.size());
     auto events = getEvents();
 
-    long lastEventTime = currentTime;
+    int64_t lastEventTime = currentTime;
     for (auto& event : events) {
         EXPECT_GT(event.timestamp, lastEventTime);
         lastEventTime = event.timestamp;
@@ -313,18 +324,11 @@
             std::make_unique<JsonFakeValueGenerator>(getTestFilePath("prop.json"), -1);
     getHub()->registerGenerator(0, std::move(generator));
 
-    // wait for some time.
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-
-    auto events = getEvents();
-
-    // Send 1 iteration takes 4ms + 1ms interval between iteration, so for 100ms we should get about
-    // 20 iteration, which is 80 events.
-    EXPECT_GT(events.size(), static_cast<size_t>(50));
+    waitForEvents(40);
 }
 
 TEST_F(FakeVehicleHalValueGeneratorsTest, testJsonFakeValueGeneratorUsingRequest) {
-    long currentTime = elapsedRealtimeNano();
+    int64_t currentTime = elapsedRealtimeNano();
 
     VehiclePropValue request = {.value = {
                                         .stringValue = getTestFilePath("prop.json"),
@@ -335,9 +339,6 @@
             std::make_unique<JsonFakeValueGenerator>(request);
     getHub()->registerGenerator(0, std::move(generator));
 
-    // wait for some time.
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-
     std::vector<VehiclePropValue> expectedValues = {
             VehiclePropValue{
                     .areaId = 0,
@@ -366,9 +367,10 @@
         expectedValues.push_back(expectedValues[i]);
     }
 
+    waitForEvents(expectedValues.size());
     auto events = getEvents();
 
-    long lastEventTime = currentTime;
+    int64_t lastEventTime = currentTime;
     for (auto& event : events) {
         EXPECT_GT(event.timestamp, lastEventTime);
         lastEventTime = event.timestamp;
@@ -388,9 +390,6 @@
             std::make_unique<JsonFakeValueGenerator>(request);
     getHub()->registerGenerator(0, std::move(generator));
 
-    // wait for some time.
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-
     ASSERT_TRUE(getEvents().empty());
 }
 
@@ -404,12 +403,79 @@
             std::make_unique<JsonFakeValueGenerator>(request);
     getHub()->registerGenerator(0, std::move(generator));
 
-    // wait for some time.
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-
     ASSERT_TRUE(getEvents().empty());
 }
 
+TEST_F(FakeVehicleHalValueGeneratorsTest, testJsonFakeValueGeneratorDifferentTypes) {
+    std::unique_ptr<JsonFakeValueGenerator> generator = std::make_unique<JsonFakeValueGenerator>(
+            getTestFilePath("prop_different_types.json"), 1);
+    getHub()->registerGenerator(0, std::move(generator));
+
+    std::vector<VehiclePropValue> expectedValues = {
+            VehiclePropValue{
+                    .areaId = 0,
+                    .value.int32Values = {1},
+                    .prop = 287310600,
+            },
+            VehiclePropValue{
+                    .areaId = 0,
+                    .value.int32Values = {2},
+                    .prop = 289408000,
+            },
+            VehiclePropValue{
+                    .areaId = 0,
+                    .value.floatValues = {3.3},
+                    .prop = 291504905,
+            },
+            VehiclePropValue{
+                    .areaId = 0,
+                    .value.int64Values = {4},
+                    .prop = 290457096,
+            },
+            VehiclePropValue{
+                    .areaId = 0,
+                    .value.stringValue = "test",
+                    .prop = 286265094,
+            },
+            VehiclePropValue{
+                    .areaId = 0,
+                    .value.int32Values = {1, 2},
+                    .prop = 289476368,
+            },
+            VehiclePropValue{
+                    .areaId = 0,
+                    .value =
+                            {
+                                    .int32Values = {1, 2},
+                                    .int64Values = {3, 4},
+                                    .floatValues = {5.5, 6.6},
+                                    .stringValue = "test",
+                            },
+                    .prop = 299896626,
+            },
+            VehiclePropValue{
+                    .areaId = 0,
+                    .value =
+                            {
+                                    .int32Values = {1},
+                                    .floatValues = {1.0},
+                                    .byteValues = {0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+                                                   0x00, 0x00, 0x00, 0x00, 0x00},
+                            },
+                    .prop = 299896064,
+            },
+    };
+
+    waitForEvents(expectedValues.size());
+    auto events = getEvents();
+
+    for (auto& event : events) {
+        event.timestamp = 0;
+    }
+
+    EXPECT_EQ(events, expectedValues);
+}
+
 }  // namespace fake
 }  // namespace vehicle
 }  // namespace automotive
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/prop_different_types.json b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/prop_different_types.json
new file mode 100644
index 0000000..0363ebd
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/prop_different_types.json
@@ -0,0 +1,58 @@
+[
+  {
+    "timestamp": 1000000,
+    "areaId": 0,
+    "value": 1,
+    "prop": 287310600
+  },
+  {
+    "timestamp": 1000000,
+    "areaId": 0,
+    "value": 2,
+    "prop": 289408000
+  },
+  {
+    "timestamp": 1000000,
+    "areaId": 0,
+    "value": 3.3,
+    "prop": 291504905
+  },
+  {
+    "timestamp": 1000000,
+    "areaId": 0,
+    "value": 4,
+    "prop": 290457096
+  },
+  {
+    "timestamp": 1000000,
+    "areaId": 0,
+    "value": "test",
+    "prop": 286265094
+  },
+  {
+    "timestamp": 1000000,
+    "areaId": 0,
+    "value": [1, 2],
+    "prop": 289476368
+  },
+  {
+    "timestamp": 1000000,
+    "areaId": 0,
+    "value": {
+      "int32Values": [1, 2],
+      "int64Values": [3, 4],
+      "floatValues": [5.5, 6.6],
+      "stringValue": "test"
+    },
+    "prop": 299896626
+  },
+  {
+    "timestamp": 1000000,
+    "areaId": 0,
+    "value": {
+      "int32Values": [1],
+      "floatValues": [1]
+    },
+    "prop": 299896064
+  }
+]
\ No newline at end of file
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index 9634c80..1c076d3 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -41,6 +41,8 @@
 
 class FakeVehicleHardware : public IVehicleHardware {
   public:
+    using ValueResultType = VhalResult<VehiclePropValuePool::RecyclableType>;
+
     FakeVehicleHardware();
 
     explicit FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> valuePool);
@@ -85,10 +87,10 @@
     const std::shared_ptr<VehiclePropValuePool> mValuePool;
     const std::shared_ptr<VehiclePropertyStore> mServerSidePropStore;
 
-    android::base::Result<VehiclePropValuePool::RecyclableType> getValue(
+    ValueResultType getValue(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
 
-    android::base::Result<void> setValue(
+    VhalResult<void> setValue(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
 
   private:
@@ -115,19 +117,19 @@
     // Override the properties using config files in 'overrideDir'.
     void overrideProperties(const char* overrideDir);
 
-    android::base::Result<void> maybeSetSpecialValue(
+    VhalResult<void> maybeSetSpecialValue(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
             bool* isSpecialValue);
-    android::base::Result<VehiclePropValuePool::RecyclableType> maybeGetSpecialValue(
+    ValueResultType maybeGetSpecialValue(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
             bool* isSpecialValue) const;
-    android::base::Result<void> setApPowerStateReport(
+    VhalResult<void> setApPowerStateReport(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
     VehiclePropValuePool::RecyclableType createApPowerStateReq(
             aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq state);
-    android::base::Result<void> setUserHalProp(
+    VhalResult<void> setUserHalProp(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
-    android::base::Result<VehiclePropValuePool::RecyclableType> getUserHalProp(
+    ValueResultType getUserHalProp(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
     bool isHvacPropAndHvacNotAvailable(int32_t propId);
 
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index 097257e..462506d 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -191,13 +191,13 @@
     return req;
 }
 
-Result<void> FakeVehicleHardware::setApPowerStateReport(const VehiclePropValue& value) {
+VhalResult<void> FakeVehicleHardware::setApPowerStateReport(const VehiclePropValue& value) {
     auto updatedValue = mValuePool->obtain(value);
     updatedValue->timestamp = elapsedRealtimeNano();
 
     if (auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
         !writeResult.ok()) {
-        return Error(getIntErrorCode(writeResult))
+        return StatusError(getErrorCode(writeResult))
                << "failed to write value into property store, error: " << getErrorMsg(writeResult);
     }
 
@@ -211,14 +211,20 @@
         case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
             [[fallthrough]];
         case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
-            // CPMS is in WAIT_FOR_VHAL state, simply move to ON
-            // Send back to HAL
-            // ALWAYS update status for generated property value
+            // CPMS is in WAIT_FOR_VHAL state, simply move to ON and send back to HAL.
+            // Must erase existing state because in the case when Car Service crashes, the power
+            // state would already be ON when we receive WAIT_FOR_VHAL and thus new property change
+            // event would be generated. However, Car Service always expect a property change event
+            // even though there is not actual state change.
+            mServerSidePropStore->removeValuesForProperty(
+                    toInt(VehicleProperty::AP_POWER_STATE_REQ));
             prop = createApPowerStateReq(VehicleApPowerStateReq::ON);
+
+            // ALWAYS update status for generated property value
             if (auto writeResult =
                         mServerSidePropStore->writeValue(std::move(prop), /*updateStatus=*/true);
                 !writeResult.ok()) {
-                return Error(getIntErrorCode(writeResult))
+                return StatusError(getErrorCode(writeResult))
                        << "failed to write AP_POWER_STATE_REQ into property store, error: "
                        << getErrorMsg(writeResult);
             }
@@ -235,7 +241,7 @@
             if (auto writeResult =
                         mServerSidePropStore->writeValue(std::move(prop), /*updateStatus=*/true);
                 !writeResult.ok()) {
-                return Error(getIntErrorCode(writeResult))
+                return StatusError(getErrorCode(writeResult))
                        << "failed to write AP_POWER_STATE_REQ into property store, error: "
                        << getErrorMsg(writeResult);
             }
@@ -262,10 +268,10 @@
     return false;
 }
 
-Result<void> FakeVehicleHardware::setUserHalProp(const VehiclePropValue& value) {
+VhalResult<void> FakeVehicleHardware::setUserHalProp(const VehiclePropValue& value) {
     auto result = mFakeUserHal->onSetProperty(value);
     if (!result.ok()) {
-        return Error(getIntErrorCode(result))
+        return StatusError(getErrorCode(result))
                << "onSetProperty(): HAL returned error: " << getErrorMsg(result);
     }
     auto& updatedValue = result.value();
@@ -274,7 +280,7 @@
               updatedValue->toString().c_str());
         if (auto writeResult = mServerSidePropStore->writeValue(std::move(result.value()));
             !writeResult.ok()) {
-            return Error(getIntErrorCode(writeResult))
+            return StatusError(getErrorCode(writeResult))
                    << "failed to write value into property store, error: "
                    << getErrorMsg(writeResult);
         }
@@ -282,14 +288,14 @@
     return {};
 }
 
-Result<VehiclePropValuePool::RecyclableType> FakeVehicleHardware::getUserHalProp(
+FakeVehicleHardware::ValueResultType FakeVehicleHardware::getUserHalProp(
         const VehiclePropValue& value) const {
     auto propId = value.prop;
     ALOGI("get(): getting value for prop %d from User HAL", propId);
 
     auto result = mFakeUserHal->onGetProperty(value);
     if (!result.ok()) {
-        return Error(getIntErrorCode(result))
+        return StatusError(getErrorCode(result))
                << "get(): User HAL returned error: " << getErrorMsg(result);
     } else {
         auto& gotValue = result.value();
@@ -298,17 +304,16 @@
             gotValue->timestamp = elapsedRealtimeNano();
             return result;
         } else {
-            return Error(toInt(StatusCode::INTERNAL_ERROR))
-                   << "get(): User HAL returned null value";
+            return StatusError(StatusCode::INTERNAL_ERROR) << "get(): User HAL returned null value";
         }
     }
 }
 
-Result<VehiclePropValuePool::RecyclableType> FakeVehicleHardware::maybeGetSpecialValue(
+FakeVehicleHardware::ValueResultType FakeVehicleHardware::maybeGetSpecialValue(
         const VehiclePropValue& value, bool* isSpecialValue) const {
     *isSpecialValue = false;
     int32_t propId = value.prop;
-    Result<VehiclePropValuePool::RecyclableType> result;
+    ValueResultType result;
 
     if (mFakeUserHal->isSupported(propId)) {
         *isSpecialValue = true;
@@ -338,8 +343,8 @@
     return nullptr;
 }
 
-Result<void> FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValue& value,
-                                                       bool* isSpecialValue) {
+VhalResult<void> FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValue& value,
+                                                           bool* isSpecialValue) {
     *isSpecialValue = false;
     VehiclePropValuePool::RecyclableType updatedValue;
     int32_t propId = value.prop;
@@ -351,7 +356,7 @@
 
     if (isHvacPropAndHvacNotAvailable(propId)) {
         *isSpecialValue = true;
-        return Error(toInt(StatusCode::NOT_AVAILABLE)) << "hvac not available";
+        return StatusError(StatusCode::NOT_AVAILABLE) << "hvac not available";
     }
 
     switch (propId) {
@@ -390,7 +395,7 @@
             updatedValue->areaId = value.areaId;
             if (auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
                 !writeResult.ok()) {
-                return Error(getIntErrorCode(writeResult))
+                return StatusError(getErrorCode(writeResult))
                        << "failed to write value into property store, error: "
                        << getErrorMsg(writeResult);
             }
@@ -435,13 +440,13 @@
     return StatusCode::OK;
 }
 
-Result<void> FakeVehicleHardware::setValue(const VehiclePropValue& value) {
+VhalResult<void> FakeVehicleHardware::setValue(const VehiclePropValue& value) {
     bool isSpecialValue = false;
     auto setSpecialValueResult = maybeSetSpecialValue(value, &isSpecialValue);
 
     if (isSpecialValue) {
         if (!setSpecialValueResult.ok()) {
-            return Error(getIntErrorCode(setSpecialValueResult))
+            return StatusError(getErrorCode(setSpecialValueResult))
                    << StringPrintf("failed to set special value for property ID: %d, error: %s",
                                    value.prop, getErrorMsg(setSpecialValueResult).c_str());
         }
@@ -454,7 +459,7 @@
 
     auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
     if (!writeResult.ok()) {
-        return Error(getIntErrorCode(writeResult))
+        return StatusError(getErrorCode(writeResult))
                << StringPrintf("failed to write value into property store, error: %s",
                                getErrorMsg(writeResult).c_str());
     }
@@ -495,13 +500,13 @@
     return StatusCode::OK;
 }
 
-Result<VehiclePropValuePool::RecyclableType> FakeVehicleHardware::getValue(
+FakeVehicleHardware::ValueResultType FakeVehicleHardware::getValue(
         const VehiclePropValue& value) const {
     bool isSpecialValue = false;
     auto result = maybeGetSpecialValue(value, &isSpecialValue);
     if (isSpecialValue) {
         if (!result.ok()) {
-            return Error(getIntErrorCode(result))
+            return StatusError(getErrorCode(result))
                    << StringPrintf("failed to get special value: %d, error: %s", value.prop,
                                    getErrorMsg(result).c_str());
         } else {
@@ -513,9 +518,9 @@
     if (!readResult.ok()) {
         StatusCode errorCode = getErrorCode(readResult);
         if (errorCode == StatusCode::NOT_AVAILABLE) {
-            return Error(toInt(errorCode)) << "value has not been set yet";
+            return StatusError(errorCode) << "value has not been set yet";
         } else {
-            return Error(toInt(errorCode))
+            return StatusError(errorCode)
                    << "failed to get value, error: " << getErrorMsg(readResult);
         }
     }
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index 0812c2a..6259f96 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -58,7 +58,6 @@
 using ::testing::ContainerEq;
 using ::testing::ContainsRegex;
 using ::testing::Eq;
-using ::testing::IsSubsetOf;
 using ::testing::WhenSortedBy;
 
 constexpr int INVALID_PROP_ID = 0;
@@ -635,16 +634,16 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
-                                            .value.int32Values = {toInt(
-                                                    VehicleApPowerStateReport::DEEP_SLEEP_EXIT)},
-                                    },
-                                    VehiclePropValue{
                                             .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
                                             .status = VehiclePropertyStatus::AVAILABLE,
                                             .value.int32Values = {toInt(VehicleApPowerStateReq::ON),
                                                                   0},
                                     },
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::DEEP_SLEEP_EXIT)},
+                                    },
                             },
             },
             SetSpecialValueTestCase{
@@ -660,16 +659,16 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
-                                            .value.int32Values = {toInt(
-                                                    VehicleApPowerStateReport::HIBERNATION_EXIT)},
-                                    },
-                                    VehiclePropValue{
                                             .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
                                             .status = VehiclePropertyStatus::AVAILABLE,
                                             .value.int32Values = {toInt(VehicleApPowerStateReq::ON),
                                                                   0},
                                     },
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::HIBERNATION_EXIT)},
+                                    },
                             },
             },
             SetSpecialValueTestCase{
@@ -685,16 +684,16 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
-                                            .value.int32Values = {toInt(
-                                                    VehicleApPowerStateReport::SHUTDOWN_CANCELLED)},
-                                    },
-                                    VehiclePropValue{
                                             .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
                                             .status = VehiclePropertyStatus::AVAILABLE,
                                             .value.int32Values = {toInt(VehicleApPowerStateReq::ON),
                                                                   0},
                                     },
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::SHUTDOWN_CANCELLED)},
+                                    },
                             },
             },
             SetSpecialValueTestCase{
@@ -710,16 +709,16 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
-                                            .value.int32Values = {toInt(
-                                                    VehicleApPowerStateReport::WAIT_FOR_VHAL)},
-                                    },
-                                    VehiclePropValue{
                                             .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
                                             .status = VehiclePropertyStatus::AVAILABLE,
                                             .value.int32Values = {toInt(VehicleApPowerStateReq::ON),
                                                                   0},
                                     },
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::WAIT_FOR_VHAL)},
+                                    },
                             },
             },
             SetSpecialValueTestCase{
@@ -735,16 +734,16 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
-                                            .value.int32Values = {toInt(
-                                                    VehicleApPowerStateReport::DEEP_SLEEP_ENTRY)},
-                                    },
-                                    VehiclePropValue{
                                             .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
                                             .status = VehiclePropertyStatus::AVAILABLE,
                                             .value.int32Values =
                                                     {toInt(VehicleApPowerStateReq::FINISHED), 0},
                                     },
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::DEEP_SLEEP_ENTRY)},
+                                    },
                             },
             },
             SetSpecialValueTestCase{
@@ -760,16 +759,16 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
-                                            .value.int32Values = {toInt(
-                                                    VehicleApPowerStateReport::HIBERNATION_ENTRY)},
-                                    },
-                                    VehiclePropValue{
                                             .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
                                             .status = VehiclePropertyStatus::AVAILABLE,
                                             .value.int32Values =
                                                     {toInt(VehicleApPowerStateReq::FINISHED), 0},
                                     },
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::HIBERNATION_ENTRY)},
+                                    },
                             },
             },
             SetSpecialValueTestCase{
@@ -785,16 +784,16 @@
                     .expectedValuesToGet =
                             {
                                     VehiclePropValue{
-                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
-                                            .value.int32Values = {toInt(
-                                                    VehicleApPowerStateReport::SHUTDOWN_START)},
-                                    },
-                                    VehiclePropValue{
                                             .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
                                             .status = VehiclePropertyStatus::AVAILABLE,
                                             .value.int32Values =
                                                     {toInt(VehicleApPowerStateReq::FINISHED), 0},
                                     },
+                                    VehiclePropValue{
+                                            .prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
+                                            .value.int32Values = {toInt(
+                                                    VehicleApPowerStateReport::SHUTDOWN_START)},
+                                    },
                             },
             },
             SetSpecialValueTestCase{
@@ -915,7 +914,7 @@
     // Some of the updated properties might be the same as default config, thus not causing
     // a property change event. So the changed properties should be a subset of all the updated
     // properties.
-    ASSERT_THAT(getChangedProperties(), WhenSortedBy(mPropValueCmp, IsSubsetOf(gotValues)));
+    ASSERT_THAT(getChangedProperties(), WhenSortedBy(mPropValueCmp, Eq(gotValues)));
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -925,6 +924,32 @@
             return info.param.name;
         });
 
+TEST_F(FakeVehicleHardwareTest, testSetWaitForVhalAfterCarServiceCrash) {
+    int32_t propId = toInt(VehicleProperty::AP_POWER_STATE_REPORT);
+    VehiclePropValue request = VehiclePropValue{
+            .prop = propId,
+            .value.int32Values = {toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL)},
+    };
+    ASSERT_EQ(setValue(request), StatusCode::OK) << "failed to set property " << propId;
+
+    // Clear existing events.
+    clearChangedProperties();
+
+    // Simulate a Car Service crash, Car Service would restart and send the message again.
+    ASSERT_EQ(setValue(request), StatusCode::OK) << "failed to set property " << propId;
+
+    std::vector<VehiclePropValue> events = getChangedProperties();
+    // Even though the state is already ON, we should receive another ON event.
+    ASSERT_EQ(events.size(), 1u);
+    // Erase the timestamp for comparison.
+    events[0].timestamp = 0;
+    ASSERT_EQ(events[0], (VehiclePropValue{
+                                 .prop = toInt(VehicleProperty::AP_POWER_STATE_REQ),
+                                 .status = VehiclePropertyStatus::AVAILABLE,
+                                 .value.int32Values = {toInt(VehicleApPowerStateReq::ON), 0},
+                         }));
+}
+
 TEST_F(FakeVehicleHardwareTest, testGetObd2FreezeFrame) {
     int64_t timestamp = elapsedRealtimeNano();
 
diff --git a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/include/FakeObd2Frame.h b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/include/FakeObd2Frame.h
index fa6d8f9..4d2ffd0 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/include/FakeObd2Frame.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/include/FakeObd2Frame.h
@@ -38,11 +38,11 @@
             const aidl::android::hardware::automotive::vehicle::VehiclePropConfig& propConfig);
     void initObd2FreezeFrame(
             const aidl::android::hardware::automotive::vehicle::VehiclePropConfig& propConfig);
-    android::base::Result<VehiclePropValuePool::RecyclableType> getObd2FreezeFrame(
+    VhalResult<VehiclePropValuePool::RecyclableType> getObd2FreezeFrame(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue&
                     requestedPropValue) const;
-    android::base::Result<VehiclePropValuePool::RecyclableType> getObd2DtcInfo() const;
-    android::base::Result<void> clearObd2FreezeFrames(
+    VhalResult<VehiclePropValuePool::RecyclableType> getObd2DtcInfo() const;
+    VhalResult<void> clearObd2FreezeFrames(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue);
     static bool isDiagnosticProperty(
             const aidl::android::hardware::automotive::vehicle::VehiclePropConfig& propConfig);
diff --git a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/src/FakeObd2Frame.cpp b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/src/FakeObd2Frame.cpp
index 5585fb4..5f9f217 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/src/FakeObd2Frame.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/src/FakeObd2Frame.cpp
@@ -44,7 +44,6 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
-using ::android::base::Error;
 using ::android::base::Result;
 
 std::unique_ptr<Obd2SensorStore> FakeObd2Frame::fillDefaultObd2Frame(size_t numVendorIntegerSensors,
@@ -126,37 +125,37 @@
     }
 }
 
-Result<VehiclePropValuePool::RecyclableType> FakeObd2Frame::getObd2FreezeFrame(
+VhalResult<VehiclePropValuePool::RecyclableType> FakeObd2Frame::getObd2FreezeFrame(
         const VehiclePropValue& requestedPropValue) const {
     if (requestedPropValue.value.int64Values.size() != 1) {
-        return Error(toInt(StatusCode::INVALID_ARG))
+        return StatusError(StatusCode::INVALID_ARG)
                << "asked for OBD2_FREEZE_FRAME without valid timestamp";
     }
     auto readValuesResult = mPropStore->readValuesForProperty(OBD2_FREEZE_FRAME);
     if (!readValuesResult.ok()) {
-        return Error(toInt(StatusCode::INTERNAL_ERROR))
+        return StatusError(StatusCode::INTERNAL_ERROR)
                << "failed to read OBD2_FREEZE_FRAME property: "
                << readValuesResult.error().message();
     }
     if (readValuesResult.value().size() == 0) {
         // Should no freeze frame be available at the given timestamp, a response of NOT_AVAILABLE
         // must be returned by the implementation
-        return Error(toInt(StatusCode::NOT_AVAILABLE));
+        return StatusError(StatusCode::NOT_AVAILABLE);
     }
     auto timestamp = requestedPropValue.value.int64Values[0];
     auto readValueResult = mPropStore->readValue(OBD2_FREEZE_FRAME, /*area=*/0, timestamp);
     if (!readValueResult.ok()) {
-        return Error(toInt(StatusCode::INVALID_ARG))
+        return StatusError(StatusCode::INVALID_ARG)
                << "asked for OBD2_FREEZE_FRAME at invalid timestamp";
     }
     return readValueResult;
 }
 
-Result<VehiclePropValuePool::RecyclableType> FakeObd2Frame::getObd2DtcInfo() const {
+VhalResult<VehiclePropValuePool::RecyclableType> FakeObd2Frame::getObd2DtcInfo() const {
     std::vector<int64_t> timestamps;
     auto result = mPropStore->readValuesForProperty(OBD2_FREEZE_FRAME);
     if (!result.ok()) {
-        return Error(toInt(StatusCode::INTERNAL_ERROR))
+        return StatusError(StatusCode::INTERNAL_ERROR)
                << "failed to read OBD2_FREEZE_FRAME property: " << result.error().message();
     }
     for (const auto& freezeFrame : result.value()) {
@@ -169,7 +168,7 @@
     return outValue;
 }
 
-Result<void> FakeObd2Frame::clearObd2FreezeFrames(const VehiclePropValue& propValue) {
+VhalResult<void> FakeObd2Frame::clearObd2FreezeFrames(const VehiclePropValue& propValue) {
     if (propValue.value.int64Values.size() == 0) {
         mPropStore->removeValuesForProperty(OBD2_FREEZE_FRAME);
         return {};
@@ -177,7 +176,7 @@
     for (int64_t timestamp : propValue.value.int64Values) {
         auto result = mPropStore->readValue(OBD2_FREEZE_FRAME, 0, timestamp);
         if (!result.ok()) {
-            return Error(toInt(StatusCode::INVALID_ARG))
+            return StatusError(StatusCode::INVALID_ARG)
                    << "asked for OBD2_FREEZE_FRAME at invalid timestamp, error: %s"
                    << result.error().message();
         }
diff --git a/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h b/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
index a220146..4ae9c8c 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
@@ -23,6 +23,7 @@
 
 #include <VehicleHalTypes.h>
 #include <VehicleObjectPool.h>
+#include <VehicleUtils.h>
 
 #include <memory>
 #include <mutex>
@@ -38,6 +39,8 @@
 // Class used to emulate a real User HAL behavior through lshal debug requests.
 class FakeUserHal final {
   public:
+    using ValueResultType = VhalResult<VehiclePropValuePool::RecyclableType>;
+
     explicit FakeUserHal(std::shared_ptr<VehiclePropValuePool> valuePool) : mValuePool(valuePool) {}
 
     ~FakeUserHal() = default;
@@ -48,13 +51,13 @@
     // Lets the emulator set the property.
     //
     // @return updated property and StatusCode
-    android::base::Result<VehiclePropValuePool::RecyclableType> onSetProperty(
+    ValueResultType onSetProperty(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
 
     // Gets the property value from the emulator.
     //
     // @return property value and StatusCode
-    android::base::Result<VehiclePropValuePool::RecyclableType> onGetProperty(
+    ValueResultType onGetProperty(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
 
     // Shows the User HAL emulation help.
@@ -93,34 +96,33 @@
     // - if it's 2, reply with mInitialUserResponseFromCmd but a wrong request id (so Android can
     // test this error scenario)
     // - if it's 3, then don't send a property change (so Android can emulate a timeout)
-    android::base::Result<VehiclePropValuePool::RecyclableType> onSetInitialUserInfoResponse(
+    ValueResultType onSetInitialUserInfoResponse(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
 
     // Used to emulate SWITCH_USER - see onSetInitialUserInfoResponse() for usage.
-    android::base::Result<VehiclePropValuePool::RecyclableType> onSetSwitchUserResponse(
+    ValueResultType onSetSwitchUserResponse(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
 
     // Used to emulate CREATE_USER - see onSetInitialUserInfoResponse() for usage.
-    android::base::Result<VehiclePropValuePool::RecyclableType> onSetCreateUserResponse(
+    ValueResultType onSetCreateUserResponse(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
 
     // Used to emulate set USER_IDENTIFICATION_ASSOCIATION - see onSetInitialUserInfoResponse() for
     // usage.
-    android::base::Result<VehiclePropValuePool::RecyclableType> onSetUserIdentificationAssociation(
+    ValueResultType onSetUserIdentificationAssociation(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
 
     // Used to emulate get USER_IDENTIFICATION_ASSOCIATION - see onSetInitialUserInfoResponse() for
     // usage.
-    android::base::Result<VehiclePropValuePool::RecyclableType> onGetUserIdentificationAssociation(
+    ValueResultType onGetUserIdentificationAssociation(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
 
     // Creates a default USER_IDENTIFICATION_ASSOCIATION when it was not set by lshal.
-    static android::base::Result<VehiclePropValuePool::RecyclableType>
-    defaultUserIdentificationAssociation(
+    static ValueResultType defaultUserIdentificationAssociation(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& request);
 
-    android::base::Result<VehiclePropValuePool::RecyclableType> sendUserHalResponse(
-            VehiclePropValuePool::RecyclableType response, int32_t requestId);
+    ValueResultType sendUserHalResponse(VehiclePropValuePool::RecyclableType response,
+                                        int32_t requestId);
 };
 
 }  // namespace fake
diff --git a/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp b/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
index 9b60053..7748fb6 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
@@ -51,20 +51,24 @@
 constexpr int32_t USER_IDENTIFICATION_ASSOCIATION =
         toInt(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
 
-Result<int32_t> getRequestId(const VehiclePropValue& value) {
+VhalResult<int32_t> getRequestId(const VehiclePropValue& value) {
     if (value.value.int32Values.size() < 1) {
-        return Error(toInt(StatusCode::INVALID_ARG))
+        return StatusError(StatusCode::INVALID_ARG)
                << "no int32Values on property: " << value.toString();
     }
     return value.value.int32Values[0];
 }
 
-Result<SwitchUserMessageType> getSwitchUserMessageType(const VehiclePropValue& value) {
+VhalResult<SwitchUserMessageType> getSwitchUserMessageType(const VehiclePropValue& value) {
     if (value.value.int32Values.size() < 2) {
-        return Error(toInt(StatusCode::INVALID_ARG))
+        return StatusError(StatusCode::INVALID_ARG)
                << "missing switch user message type on property: " << value.toString();
     }
-    return user_hal_helper::verifyAndCast<SwitchUserMessageType>(value.value.int32Values[1]);
+    auto result = user_hal_helper::verifyAndCast<SwitchUserMessageType>(value.value.int32Values[1]);
+    if (!result.ok()) {
+        return StatusError(StatusCode::INVALID_ARG) << result.error().message();
+    }
+    return result.value();
 }
 
 }  // namespace
@@ -82,8 +86,7 @@
     }
 }
 
-Result<VehiclePropValuePool::RecyclableType> FakeUserHal::onSetProperty(
-        const VehiclePropValue& value) {
+FakeUserHal::ValueResultType FakeUserHal::onSetProperty(const VehiclePropValue& value) {
     ALOGV("onSetProperty(): %s", value.toString().c_str());
 
     switch (value.prop) {
@@ -99,13 +102,12 @@
         case USER_IDENTIFICATION_ASSOCIATION:
             return onSetUserIdentificationAssociation(value);
         default:
-            return Error(toInt(StatusCode::INVALID_ARG))
+            return StatusError(StatusCode::INVALID_ARG)
                    << "Unsupported property: " << value.toString();
     }
 }
 
-Result<VehiclePropValuePool::RecyclableType> FakeUserHal::onGetProperty(
-        const VehiclePropValue& value) const {
+FakeUserHal::ValueResultType FakeUserHal::onGetProperty(const VehiclePropValue& value) const {
     ALOGV("onGetProperty(%s)", value.toString().c_str());
     switch (value.prop) {
         case INITIAL_USER_INFO:
@@ -113,16 +115,16 @@
         case CREATE_USER:
         case REMOVE_USER:
             ALOGE("onGetProperty(): %d is only supported on SET", value.prop);
-            return Error(toInt(StatusCode::INVALID_ARG)) << "only supported on SET";
+            return StatusError(StatusCode::INVALID_ARG) << "only supported on SET";
         case USER_IDENTIFICATION_ASSOCIATION:
             return onGetUserIdentificationAssociation(value);
         default:
             ALOGE("onGetProperty(): %d is not supported", value.prop);
-            return Error(toInt(StatusCode::INVALID_ARG)) << "not supported by User HAL";
+            return StatusError(StatusCode::INVALID_ARG) << "not supported by User HAL";
     }
 }
 
-Result<VehiclePropValuePool::RecyclableType> FakeUserHal::onGetUserIdentificationAssociation(
+FakeUserHal::ValueResultType FakeUserHal::onGetUserIdentificationAssociation(
         const VehiclePropValue& value) const {
     std::scoped_lock<std::mutex> lockGuard(mLock);
 
@@ -143,7 +145,7 @@
     return newValue;
 }
 
-Result<VehiclePropValuePool::RecyclableType> FakeUserHal::onSetInitialUserInfoResponse(
+FakeUserHal::ValueResultType FakeUserHal::onSetInitialUserInfoResponse(
         const VehiclePropValue& value) {
     std::scoped_lock<std::mutex> lockGuard(mLock);
 
@@ -178,8 +180,7 @@
     return updatedValue;
 }
 
-Result<VehiclePropValuePool::RecyclableType> FakeUserHal::onSetSwitchUserResponse(
-        const VehiclePropValue& value) {
+FakeUserHal::ValueResultType FakeUserHal::onSetSwitchUserResponse(const VehiclePropValue& value) {
     std::scoped_lock<std::mutex> lockGuard(mLock);
 
     auto requestId = getRequestId(value);
@@ -234,8 +235,7 @@
     return updatedValue;
 }
 
-Result<VehiclePropValuePool::RecyclableType> FakeUserHal::onSetCreateUserResponse(
-        const VehiclePropValue& value) {
+FakeUserHal::ValueResultType FakeUserHal::onSetCreateUserResponse(const VehiclePropValue& value) {
     std::scoped_lock<std::mutex> lockGuard(mLock);
 
     auto requestId = getRequestId(value);
@@ -268,7 +268,7 @@
     return updatedValue;
 }
 
-Result<VehiclePropValuePool::RecyclableType> FakeUserHal::onSetUserIdentificationAssociation(
+FakeUserHal::ValueResultType FakeUserHal::onSetUserIdentificationAssociation(
         const VehiclePropValue& value) {
     std::scoped_lock<std::mutex> lockGuard(mLock);
 
@@ -298,14 +298,14 @@
     return defaultUserIdentificationAssociation(value);
 }
 
-Result<VehiclePropValuePool::RecyclableType> FakeUserHal::defaultUserIdentificationAssociation(
+FakeUserHal::ValueResultType FakeUserHal::defaultUserIdentificationAssociation(
         const VehiclePropValue& request) {
     // TODO(b/159498909): return a response with NOT_ASSOCIATED_ANY_USER for all requested types
     ALOGE("no lshal response for %s; replying with NOT_AVAILABLE", request.toString().c_str());
-    return Error(toInt(StatusCode::NOT_AVAILABLE)) << "not set by lshal";
+    return StatusError(StatusCode::NOT_AVAILABLE) << "not set by lshal";
 }
 
-Result<VehiclePropValuePool::RecyclableType> FakeUserHal::sendUserHalResponse(
+FakeUserHal::ValueResultType FakeUserHal::sendUserHalResponse(
         VehiclePropValuePool::RecyclableType response, int32_t requestId) {
     switch (response->areaId) {
         case 1:
@@ -319,12 +319,12 @@
         case 3:
             ALOGD("not generating a property change event because of lshal prop: %s",
                   response->toString().c_str());
-            return Error(toInt(StatusCode::NOT_AVAILABLE))
+            return StatusError(StatusCode::NOT_AVAILABLE)
                    << "not generating a property change event because of lshal prop: "
                    << response->toString();
         default:
             ALOGE("invalid action on lshal response: %s", response->toString().c_str());
-            return Error(toInt(StatusCode::INTERNAL_ERROR))
+            return StatusError(StatusCode::INTERNAL_ERROR)
                    << "invalid action on lshal response: " << response->toString();
     }
 
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/ConcurrentQueue.h b/automotive/vehicle/aidl/impl/utils/common/include/ConcurrentQueue.h
index 08b56a6..327c0dc 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/ConcurrentQueue.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/ConcurrentQueue.h
@@ -33,12 +33,13 @@
 template <typename T>
 class ConcurrentQueue {
   public:
-    void waitForItems() {
+    bool waitForItems() {
         std::unique_lock<std::mutex> lockGuard(mLock);
         android::base::ScopedLockAssertion lockAssertion(mLock);
         while (mQueue.empty() && mIsActive) {
             mCond.wait(lockGuard);
         }
+        return mIsActive;
     }
 
     std::vector<T> flush() {
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/PendingRequestPool.h b/automotive/vehicle/aidl/impl/utils/common/include/PendingRequestPool.h
index dcf5057..3f8db93 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/PendingRequestPool.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/PendingRequestPool.h
@@ -17,6 +17,7 @@
 #ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_PendingRequestPool_H_
 #define android_hardware_automotive_vehicle_aidl_impl_vhal_include_PendingRequestPool_H_
 
+#include <VehicleUtils.h>
 #include <android-base/result.h>
 #include <android-base/thread_annotations.h>
 
@@ -49,9 +50,9 @@
     // added. Otherwise, they would be added to the request pool.
     // The callback would be called if requests are not finished within {@code mTimeoutInNano}
     // seconds.
-    android::base::Result<void> addRequests(const void* clientId,
-                                            const std::unordered_set<int64_t>& requestIds,
-                                            std::shared_ptr<const TimeoutCallbackFunc> callback);
+    VhalResult<void> addRequests(const void* clientId,
+                                 const std::unordered_set<int64_t>& requestIds,
+                                 std::shared_ptr<const TimeoutCallbackFunc> callback);
 
     // Checks whether the request is currently pending.
     bool isRequestPending(const void* clientId, int64_t requestId) const;
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h b/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
index 2c7aa97..ddc4f68 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
@@ -25,6 +25,7 @@
 
 #include <VehicleHalTypes.h>
 #include <VehicleObjectPool.h>
+#include <VehicleUtils.h>
 #include <android-base/result.h>
 #include <android-base/thread_annotations.h>
 
@@ -42,6 +43,9 @@
 // This class is thread-safe, however it uses blocking synchronization across all methods.
 class VehiclePropertyStore final {
   public:
+    using ValueResultType = VhalResult<VehiclePropValuePool::RecyclableType>;
+    using ValuesResultType = VhalResult<std::vector<VehiclePropValuePool::RecyclableType>>;
+
     explicit VehiclePropertyStore(std::shared_ptr<VehiclePropValuePool> valuePool)
         : mValuePool(valuePool) {}
 
@@ -68,8 +72,8 @@
     // 'status' would be initialized to {@code VehiclePropertyStatus::AVAILABLE}, if this is to
     // override an existing value, the status for the existing value would be used for the
     // overridden value.
-    android::base::Result<void> writeValue(VehiclePropValuePool::RecyclableType propValue,
-                                           bool updateStatus = false);
+    VhalResult<void> writeValue(VehiclePropValuePool::RecyclableType propValue,
+                                bool updateStatus = false);
 
     // Remove a given property value from the property store. The 'propValue' would be used to
     // generate the key for the value to remove.
@@ -83,28 +87,26 @@
     std::vector<VehiclePropValuePool::RecyclableType> readAllValues() const;
 
     // Read all the values for the property.
-    android::base::Result<std::vector<VehiclePropValuePool::RecyclableType>> readValuesForProperty(
-            int32_t propId) const;
+    ValuesResultType readValuesForProperty(int32_t propId) const;
 
     // Read the value for the requested property. Returns {@code StatusCode::NOT_AVAILABLE} if the
     // value has not been set yet. Returns {@code StatusCode::INVALID_ARG} if the property is
     // not configured.
-    android::base::Result<VehiclePropValuePool::RecyclableType> readValue(
+    ValueResultType readValue(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& request) const;
 
     // Read the value for the requested property. Returns {@code StatusCode::NOT_AVAILABLE} if the
     // value has not been set yet. Returns {@code StatusCode::INVALID_ARG} if the property is
     // not configured.
-    android::base::Result<VehiclePropValuePool::RecyclableType> readValue(int32_t prop,
-                                                                          int32_t area = 0,
-                                                                          int64_t token = 0) const;
+    ValueResultType readValue(int32_t prop, int32_t area = 0, int64_t token = 0) const;
 
     // Get all property configs.
     std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig> getAllConfigs()
             const;
 
     // Get the property config for the requested property.
-    android::base::Result<const aidl::android::hardware::automotive::vehicle::VehiclePropConfig*>
+    android::base::Result<const aidl::android::hardware::automotive::vehicle::VehiclePropConfig*,
+                          VhalError>
     getConfig(int32_t propId) const;
 
     // Set a callback that would be called when a property value has been updated.
@@ -146,8 +148,7 @@
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue,
             const Record& record) const;
 
-    android::base::Result<VehiclePropValuePool::RecyclableType> readValueLocked(
-            const RecordId& recId, const Record& record) const;
+    ValueResultType readValueLocked(const RecordId& recId, const Record& record) const;
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
index 1fc5613..6d7d131 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
@@ -190,59 +190,6 @@
     return size;
 }
 
-template <class T>
-aidl::android::hardware::automotive::vehicle::StatusCode getErrorCode(
-        const android::base::Result<T>& result) {
-    if (result.ok()) {
-        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
-    }
-    return static_cast<aidl::android::hardware::automotive::vehicle::StatusCode>(
-            result.error().code());
-}
-
-template <class T>
-int getIntErrorCode(const android::base::Result<T>& result) {
-    return toInt(getErrorCode(result));
-}
-
-template <class T>
-std::string getErrorMsg(const android::base::Result<T>& result) {
-    if (result.ok()) {
-        return "";
-    }
-    return result.error().message();
-}
-
-template <class T>
-ndk::ScopedAStatus toScopedAStatus(const android::base::Result<T>& result,
-                                   aidl::android::hardware::automotive::vehicle::StatusCode status,
-                                   const std::string& additionalErrorMsg) {
-    if (result.ok()) {
-        return ndk::ScopedAStatus::ok();
-    }
-    return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
-            toInt(status),
-            fmt::format("{}, error: {}", additionalErrorMsg, getErrorMsg(result)).c_str());
-}
-
-template <class T>
-ndk::ScopedAStatus toScopedAStatus(
-        const android::base::Result<T>& result,
-        aidl::android::hardware::automotive::vehicle::StatusCode status) {
-    return toScopedAStatus(result, status, "");
-}
-
-template <class T>
-ndk::ScopedAStatus toScopedAStatus(const android::base::Result<T>& result) {
-    return toScopedAStatus(result, getErrorCode(result));
-}
-
-template <class T>
-ndk::ScopedAStatus toScopedAStatus(const android::base::Result<T>& result,
-                                   const std::string& additionalErrorMsg) {
-    return toScopedAStatus(result, getErrorCode(result), additionalErrorMsg);
-}
-
 // Check whether the value is valid according to config.
 // We check for the following:
 // *  If the type is INT32, {@code value.int32Values} must contain one element.
@@ -283,6 +230,86 @@
         const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
         const aidl::android::hardware::automotive::vehicle::VehicleAreaConfig* config);
 
+// VhalError is a wrapper class for {@code StatusCode} that could act as E in {@code Result<T,E>}.
+class VhalError final {
+  public:
+    VhalError() : mCode(aidl::android::hardware::automotive::vehicle::StatusCode::OK) {}
+
+    VhalError(aidl::android::hardware::automotive::vehicle::StatusCode&& code) : mCode(code) {}
+
+    VhalError(const aidl::android::hardware::automotive::vehicle::StatusCode& code) : mCode(code) {}
+
+    aidl::android::hardware::automotive::vehicle::StatusCode value() const;
+
+    inline operator aidl::android::hardware::automotive::vehicle::StatusCode() const {
+        return value();
+    }
+
+    std::string print() const;
+
+  private:
+    aidl::android::hardware::automotive::vehicle::StatusCode mCode;
+};
+
+// VhalResult is a {@code Result} that contains {@code StatusCode} as error type.
+template <class T>
+using VhalResult = android::base::Result<T, VhalError>;
+
+// StatusError could be cast to {@code ResultError} with a {@code StatusCode} and should be used
+// as error type for {@VhalResult}.
+using StatusError = android::base::Error<VhalError>;
+
+template <class T>
+aidl::android::hardware::automotive::vehicle::StatusCode getErrorCode(const VhalResult<T>& result) {
+    if (result.ok()) {
+        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+    }
+    return result.error().code();
+}
+
+template <class T>
+int getIntErrorCode(const VhalResult<T>& result) {
+    return toInt(getErrorCode(result));
+}
+
+template <class T, class E>
+std::string getErrorMsg(const android::base::Result<T, E>& result) {
+    if (result.ok()) {
+        return "";
+    }
+    return result.error().message();
+}
+
+template <class T, class E>
+ndk::ScopedAStatus toScopedAStatus(const android::base::Result<T, E>& result,
+                                   aidl::android::hardware::automotive::vehicle::StatusCode status,
+                                   const std::string& additionalErrorMsg) {
+    if (result.ok()) {
+        return ndk::ScopedAStatus::ok();
+    }
+    return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+            toInt(status),
+            fmt::format("{}, error: {}", additionalErrorMsg, getErrorMsg(result)).c_str());
+}
+
+template <class T, class E>
+ndk::ScopedAStatus toScopedAStatus(
+        const android::base::Result<T, E>& result,
+        aidl::android::hardware::automotive::vehicle::StatusCode status) {
+    return toScopedAStatus(result, status, "");
+}
+
+template <class T>
+ndk::ScopedAStatus toScopedAStatus(const VhalResult<T>& result) {
+    return toScopedAStatus(result, getErrorCode(result));
+}
+
+template <class T>
+ndk::ScopedAStatus toScopedAStatus(const VhalResult<T>& result,
+                                   const std::string& additionalErrorMsg) {
+    return toScopedAStatus(result, getErrorCode(result), additionalErrorMsg);
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/PendingRequestPool.cpp b/automotive/vehicle/aidl/impl/utils/common/src/PendingRequestPool.cpp
index 23a5403..0196edd 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/PendingRequestPool.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/PendingRequestPool.cpp
@@ -32,11 +32,10 @@
 namespace {
 
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
-using ::android::base::Error;
 using ::android::base::Result;
 
 // At least check every 1s.
-constexpr int64_t CHECK_TIME_IN_NANO = 1000000000;
+constexpr int64_t CHECK_TIME_IN_NANO = 1'000'000'000;
 
 }  // namespace
 
@@ -72,9 +71,9 @@
     }
 }
 
-Result<void> PendingRequestPool::addRequests(const void* clientId,
-                                             const std::unordered_set<int64_t>& requestIds,
-                                             std::shared_ptr<const TimeoutCallbackFunc> callback) {
+VhalResult<void> PendingRequestPool::addRequests(
+        const void* clientId, const std::unordered_set<int64_t>& requestIds,
+        std::shared_ptr<const TimeoutCallbackFunc> callback) {
     std::scoped_lock<std::mutex> lockGuard(mLock);
     std::list<PendingRequest>* pendingRequests;
     size_t pendingRequestCount = 0;
@@ -84,7 +83,7 @@
             const auto& pendingRequestIds = pendingRequest.requestIds;
             for (int64_t requestId : requestIds) {
                 if (pendingRequestIds.find(requestId) != pendingRequestIds.end()) {
-                    return Error(toInt(StatusCode::INVALID_ARG))
+                    return StatusError(StatusCode::INVALID_ARG)
                            << "duplicate request ID: " << requestId;
                 }
             }
@@ -96,7 +95,7 @@
     }
 
     if (requestIds.size() > MAX_PENDING_REQUEST_PER_CLIENT - pendingRequestCount) {
-        return Error(toInt(StatusCode::TRY_AGAIN)) << "too many pending requests";
+        return StatusError(StatusCode::TRY_AGAIN) << "too many pending requests";
     }
 
     int64_t currentTime = elapsedRealtimeNano();
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
index c1fa896..c8fb994 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -36,7 +36,6 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
-using ::android::base::Error;
 using ::android::base::Result;
 using ::android::base::StringPrintf;
 
@@ -87,12 +86,12 @@
     return recId;
 }
 
-Result<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readValueLocked(
+VhalResult<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readValueLocked(
         const RecordId& recId, const Record& record) const REQUIRES(mLock) {
     if (auto it = record.values.find(recId); it != record.values.end()) {
         return mValuePool->obtain(*(it->second));
     }
-    return Error(toInt(StatusCode::NOT_AVAILABLE))
+    return StatusError(StatusCode::NOT_AVAILABLE)
            << "Record ID: " << recId.toString() << " is not found";
 }
 
@@ -106,19 +105,19 @@
     };
 }
 
-Result<void> VehiclePropertyStore::writeValue(VehiclePropValuePool::RecyclableType propValue,
-                                              bool updateStatus) {
+VhalResult<void> VehiclePropertyStore::writeValue(VehiclePropValuePool::RecyclableType propValue,
+                                                  bool updateStatus) {
     std::scoped_lock<std::mutex> g(mLock);
 
     int32_t propId = propValue->prop;
 
     VehiclePropertyStore::Record* record = getRecordLocked(propId);
     if (record == nullptr) {
-        return Error(toInt(StatusCode::INVALID_ARG)) << "property: " << propId << " not registered";
+        return StatusError(StatusCode::INVALID_ARG) << "property: " << propId << " not registered";
     }
 
     if (!isGlobalProp(propId) && getAreaConfig(*propValue, record->propConfig) == nullptr) {
-        return Error(toInt(StatusCode::INVALID_ARG))
+        return StatusError(StatusCode::INVALID_ARG)
                << "no config for property: " << propId << " area: " << propValue->areaId;
     }
 
@@ -130,7 +129,7 @@
         VehiclePropertyStatus oldStatus = valueToUpdate->status;
         // propValue is outdated and drops it.
         if (oldTimestamp > propValue->timestamp) {
-            return Error(toInt(StatusCode::INVALID_ARG))
+            return StatusError(StatusCode::INVALID_ARG)
                    << "outdated timestamp: " << propValue->timestamp;
         }
         if (!updateStatus) {
@@ -191,15 +190,15 @@
     return allValues;
 }
 
-Result<std::vector<VehiclePropValuePool::RecyclableType>>
-VehiclePropertyStore::readValuesForProperty(int32_t propId) const {
+VehiclePropertyStore::ValuesResultType VehiclePropertyStore::readValuesForProperty(
+        int32_t propId) const {
     std::scoped_lock<std::mutex> g(mLock);
 
     std::vector<VehiclePropValuePool::RecyclableType> values;
 
     const VehiclePropertyStore::Record* record = getRecordLocked(propId);
     if (record == nullptr) {
-        return Error(toInt(StatusCode::INVALID_ARG)) << "property: " << propId << " not registered";
+        return StatusError(StatusCode::INVALID_ARG) << "property: " << propId << " not registered";
     }
 
     for (auto const& [_, value] : record->values) {
@@ -208,28 +207,28 @@
     return values;
 }
 
-Result<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readValue(
+VehiclePropertyStore::ValueResultType VehiclePropertyStore::readValue(
         const VehiclePropValue& propValue) const {
     std::scoped_lock<std::mutex> g(mLock);
 
     int32_t propId = propValue.prop;
     const VehiclePropertyStore::Record* record = getRecordLocked(propId);
     if (record == nullptr) {
-        return Error(toInt(StatusCode::INVALID_ARG)) << "property: " << propId << " not registered";
+        return StatusError(StatusCode::INVALID_ARG) << "property: " << propId << " not registered";
     }
 
     VehiclePropertyStore::RecordId recId = getRecordIdLocked(propValue, *record);
     return readValueLocked(recId, *record);
 }
 
-Result<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readValue(int32_t propId,
-                                                                             int32_t areaId,
-                                                                             int64_t token) const {
+VehiclePropertyStore::ValueResultType VehiclePropertyStore::readValue(int32_t propId,
+                                                                      int32_t areaId,
+                                                                      int64_t token) const {
     std::scoped_lock<std::mutex> g(mLock);
 
     const VehiclePropertyStore::Record* record = getRecordLocked(propId);
     if (record == nullptr) {
-        return Error(toInt(StatusCode::INVALID_ARG)) << "property: " << propId << " not registered";
+        return StatusError(StatusCode::INVALID_ARG) << "property: " << propId << " not registered";
     }
 
     VehiclePropertyStore::RecordId recId{.area = isGlobalProp(propId) ? 0 : areaId, .token = token};
@@ -247,12 +246,12 @@
     return configs;
 }
 
-Result<const VehiclePropConfig*> VehiclePropertyStore::getConfig(int32_t propId) const {
+VhalResult<const VehiclePropConfig*> VehiclePropertyStore::getConfig(int32_t propId) const {
     std::scoped_lock<std::mutex> g(mLock);
 
     const VehiclePropertyStore::Record* record = getRecordLocked(propId);
     if (record == nullptr) {
-        return Error(toInt(StatusCode::INVALID_ARG)) << "property: " << propId << " not registered";
+        return StatusError(StatusCode::INVALID_ARG) << "property: " << propId << " not registered";
     }
 
     return &record->propConfig;
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
index 5abde8d..f85728d 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
@@ -21,6 +21,7 @@
 namespace automotive {
 namespace vehicle {
 
+using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
@@ -204,6 +205,14 @@
     return {};
 }
 
+StatusCode VhalError::value() const {
+    return mCode;
+}
+
+std::string VhalError::print() const {
+    return aidl::android::hardware::automotive::vehicle::toString(mCode);
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/Android.bp b/automotive/vehicle/aidl/impl/utils/common/test/Android.bp
index 5b41ff4..250b331 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/Android.bp
@@ -19,7 +19,7 @@
 }
 
 cc_test {
-    name: "VehicleHalVehicleUtilsVendorTest",
+    name: "VehicleHalVehicleUtilsTest",
     srcs: ["*.cpp"],
     vendor: true,
     static_libs: [
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/PendingRequestPoolTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/PendingRequestPoolTest.cpp
index 9c9e4b9..734c739 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/PendingRequestPoolTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/PendingRequestPoolTest.cpp
@@ -263,7 +263,7 @@
     auto result = getPool()->addRequests(reinterpret_cast<const void*>(0),
                                          {static_cast<int64_t>(10000)}, callback);
     ASSERT_FALSE(result.ok()) << "adding more pending requests than limit must fail";
-    ASSERT_EQ(result.error().code(), toInt(StatusCode::TRY_AGAIN));
+    ASSERT_EQ(result.error().code(), StatusCode::TRY_AGAIN);
 
     getPool()->tryFinishRequests(reinterpret_cast<const void*>(0), requests);
 }
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
index 1f230e7..4d6f811 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
@@ -37,7 +37,6 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
-using ::android::base::Result;
 using ::testing::ElementsAre;
 using ::testing::Eq;
 using ::testing::WhenSortedBy;
@@ -103,7 +102,7 @@
 }
 
 TEST_F(VehiclePropertyStoreTest, testGetConfig) {
-    Result<const VehiclePropConfig*> result =
+    VhalResult<const VehiclePropConfig*> result =
             mStore->getConfig(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
 
     ASSERT_RESULT_OK(result);
@@ -111,10 +110,10 @@
 }
 
 TEST_F(VehiclePropertyStoreTest, testGetConfigWithInvalidPropId) {
-    Result<const VehiclePropConfig*> result = mStore->getConfig(INVALID_PROP_ID);
+    VhalResult<const VehiclePropConfig*> result = mStore->getConfig(INVALID_PROP_ID);
 
     EXPECT_FALSE(result.ok()) << "expect error when getting a config for an invalid property ID";
-    EXPECT_EQ(result.error().code(), toInt(StatusCode::INVALID_ARG));
+    EXPECT_EQ(result.error().code(), StatusCode::INVALID_ARG);
 }
 
 std::vector<VehiclePropValue> getTestPropValues() {
@@ -184,7 +183,7 @@
     auto result = mStore->readValuesForProperty(INVALID_PROP_ID);
 
     EXPECT_FALSE(result.ok()) << "expect error when reading values for an invalid property";
-    EXPECT_EQ(result.error().code(), toInt(StatusCode::INVALID_ARG));
+    EXPECT_EQ(result.error().code(), StatusCode::INVALID_ARG);
 }
 
 TEST_F(VehiclePropertyStoreTest, testReadValueOk) {
@@ -224,7 +223,7 @@
     auto result = mStore->readValue(toInt(VehicleProperty::TIRE_PRESSURE), WHEEL_REAR_LEFT);
 
     EXPECT_FALSE(result.ok()) << "expect error when reading a value that has not been written";
-    EXPECT_EQ(result.error().code(), toInt(StatusCode::NOT_AVAILABLE));
+    EXPECT_EQ(result.error().code(), StatusCode::NOT_AVAILABLE);
 }
 
 TEST_F(VehiclePropertyStoreTest, testWriteValueError) {
@@ -235,7 +234,7 @@
     auto result = mStore->writeValue(std::move(v));
 
     EXPECT_FALSE(result.ok()) << "expect error when writing value for an invalid property ID";
-    EXPECT_EQ(result.error().code(), toInt(StatusCode::INVALID_ARG));
+    EXPECT_EQ(result.error().code(), StatusCode::INVALID_ARG);
 }
 
 TEST_F(VehiclePropertyStoreTest, testWriteValueNoAreaConfig) {
@@ -248,7 +247,7 @@
     auto result = mStore->writeValue(std::move(v));
 
     EXPECT_FALSE(result.ok()) << "expect error when writing value for an area without config";
-    EXPECT_EQ(result.error().code(), toInt(StatusCode::INVALID_ARG));
+    EXPECT_EQ(result.error().code(), StatusCode::INVALID_ARG);
 }
 
 TEST_F(VehiclePropertyStoreTest, testWriteOutdatedValue) {
@@ -269,7 +268,7 @@
     auto result = mStore->writeValue(std::move(v2));
 
     EXPECT_FALSE(result.ok()) << "expect error when writing an outdated value";
-    EXPECT_EQ(result.error().code(), toInt(StatusCode::INVALID_ARG));
+    EXPECT_EQ(result.error().code(), StatusCode::INVALID_ARG);
 }
 
 TEST_F(VehiclePropertyStoreTest, testToken) {
@@ -317,7 +316,7 @@
     auto result = mStore->readValue(values[0]);
 
     EXPECT_FALSE(result.ok()) << "expect error when reading a removed value";
-    EXPECT_EQ(result.error().code(), toInt(StatusCode::NOT_AVAILABLE));
+    EXPECT_EQ(result.error().code(), StatusCode::NOT_AVAILABLE);
 
     auto leftTirePressureResult = mStore->readValue(values[1]);
 
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
index de8b26d..411539b 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
@@ -32,6 +32,7 @@
 
 namespace {
 
+using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
@@ -39,6 +40,8 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::android::base::Error;
+using ::android::base::Result;
 
 struct InvalidPropValueTestCase {
     std::string name;
@@ -759,6 +762,12 @@
     t.join();
 }
 
+TEST(VehicleUtilsTest, testVhalError) {
+    VhalResult<void> result = Error<VhalError>(StatusCode::INVALID_ARG) << "error message";
+
+    ASSERT_EQ(result.error().message(), "error message: INVALID_ARG");
+}
+
 class InvalidPropValueTest : public testing::TestWithParam<InvalidPropValueTestCase> {};
 
 INSTANTIATE_TEST_SUITE_P(InvalidPropValueTests, InvalidPropValueTest,
diff --git a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
index 5d88f7c..2e7298f 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
@@ -21,6 +21,7 @@
 
 #include <IVehicleHardware.h>
 #include <VehicleHalTypes.h>
+#include <VehicleUtils.h>
 
 #include <aidl/android/hardware/automotive/vehicle/IVehicleCallback.h>
 #include <android-base/result.h>
@@ -57,7 +58,7 @@
     // Returns {@code INVALID_ARG} error if any of the requestIds are duplicate with one of the
     // pending request IDs or {@code TRY_AGAIN} error if the pending request pool is full and could
     // no longer add requests.
-    android::base::Result<void> addRequests(const std::unordered_set<int64_t>& requestIds);
+    VhalResult<void> addRequests(const std::unordered_set<int64_t>& requestIds);
 
     // Marks the requests as finished. Returns a list of request IDs that was pending and has been
     // finished. It must be a set of the requested request IDs.
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index 9735ed3..f646b6b 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -22,6 +22,7 @@
 #include "PendingRequestPool.h"
 #include "SubscriptionManager.h"
 
+#include <ConcurrentQueue.h>
 #include <IVehicleHardware.h>
 #include <VehicleUtils.h>
 #include <aidl/android/hardware/automotive/vehicle/BnVehicle.h>
@@ -31,6 +32,7 @@
 
 #include <memory>
 #include <mutex>
+#include <shared_mutex>
 #include <unordered_map>
 #include <vector>
 
@@ -104,6 +106,8 @@
       public:
         SubscriptionClients(std::shared_ptr<PendingRequestPool> pool) : mPendingRequestPool(pool) {}
 
+        std::shared_ptr<SubscriptionClient> maybeAddClient(const CallbackType& callback);
+
         std::shared_ptr<SubscriptionClient> getClient(const CallbackType& callback);
 
         void removeClient(const AIBinder* clientId);
@@ -118,20 +122,24 @@
         std::shared_ptr<PendingRequestPool> mPendingRequestPool;
     };
 
-    // A wrapper for linkToDeath to enable stubbing for test.
-    class ILinkToDeath {
+    // A wrapper for binder operations to enable stubbing for test.
+    class IBinder {
       public:
-        virtual ~ILinkToDeath() = default;
+        virtual ~IBinder() = default;
 
         virtual binder_status_t linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                             void* cookie) = 0;
+
+        virtual bool isAlive(const AIBinder* binder) = 0;
     };
 
-    // A real implementation for ILinkToDeath.
-    class AIBinderLinkToDeathImpl final : public ILinkToDeath {
+    // A real implementation for IBinder.
+    class AIBinderImpl final : public IBinder {
       public:
         binder_status_t linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                     void* cookie) override;
+
+        bool isAlive(const AIBinder* binder) override;
     };
 
     // OnBinderDiedContext is a type used as a cookie passed deathRecipient. The deathRecipient's
@@ -142,6 +150,13 @@
         const AIBinder* clientId;
     };
 
+    // BinderDiedUnlinkedEvent represents either an onBinderDied or an onBinderUnlinked event.
+    struct BinderDiedUnlinkedEvent {
+        // true for onBinderDied, false for onBinderUnlinked.
+        bool onBinderDied;
+        const AIBinder* clientId;
+    };
+
     // The default timeout of get or set value requests is 30s.
     // TODO(b/214605968): define TIMEOUT_IN_NANO in IVehicle and allow getValues/setValues/subscribe
     // to specify custom timeouts.
@@ -170,14 +185,20 @@
             GUARDED_BY(mLock);
     // SubscriptionClients is thread-safe.
     std::shared_ptr<SubscriptionClients> mSubscriptionClients;
-    // mLinkToDeathImpl is only going to be changed in test.
-    std::unique_ptr<ILinkToDeath> mLinkToDeathImpl;
+    // mBinderImpl is only going to be changed in test.
+    std::unique_ptr<IBinder> mBinderImpl;
 
     // RecurrentTimer is thread-safe.
     RecurrentTimer mRecurrentTimer;
 
     ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
 
+    // ConcurrentQueue is thread-safe.
+    ConcurrentQueue<BinderDiedUnlinkedEvent> mBinderEvents;
+
+    // A thread to handle onBinderDied or onBinderUnlinked event.
+    std::thread mOnBinderDiedUnlinkedHandlerThread;
+
     android::base::Result<void> checkProperty(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue);
 
@@ -189,14 +210,14 @@
             const std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>&
                     requests);
 
-    android::base::Result<void> checkSubscribeOptions(
+    VhalResult<void> checkSubscribeOptions(
             const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
                     options);
 
-    android::base::Result<void> checkReadPermission(
+    VhalResult<void> checkReadPermission(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
 
-    android::base::Result<void> checkWritePermission(
+    VhalResult<void> checkWritePermission(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
 
     android::base::Result<const aidl::android::hardware::automotive::vehicle::VehiclePropConfig*>
@@ -206,10 +227,17 @@
 
     void onBinderUnlinkedWithContext(const AIBinder* clientId);
 
-    void monitorBinderLifeCycle(const CallbackType& callback);
+    // Registers a onBinderDied callback for the client if not already registered.
+    // Returns true if the client Binder is alive, false otherwise.
+    bool monitorBinderLifeCycleLocked(const AIBinder* clientId) REQUIRES(mLock);
 
     bool checkDumpPermission();
 
+    // The looping handler function to process all onBinderDied or onBinderUnlinked events in
+    // mBinderEvents.
+    void onBinderDiedUnlinkedHandler();
+
+    // Gets or creates a {@code T} object for the client to or from {@code clients}.
     template <class T>
     static std::shared_ptr<T> getOrCreateClient(
             std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
@@ -238,7 +266,7 @@
     void setTimeout(int64_t timeoutInNano);
 
     // Test-only
-    void setLinkToDeathImpl(std::unique_ptr<ILinkToDeath> impl);
+    void setBinderImpl(std::unique_ptr<IBinder> impl);
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
index 098bfee..81d231c 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
@@ -67,8 +67,10 @@
     parcelableResults.payloads[0] = result;
     if (ScopedAStatus callbackStatus = callCallback(callback, parcelableResults);
         !callbackStatus.isOk()) {
-        ALOGE("failed to call callback, error: %s, code: %d", callbackStatus.getMessage(),
-              callbackStatus.getServiceSpecificError());
+        ALOGE("failed to call GetOrSetValueResult callback, client ID: %p, error: %s, "
+              "exception: %d, service specific error: %d",
+              callback->asBinder().get(), callbackStatus.getMessage(),
+              callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
     }
 }
 
@@ -90,8 +92,10 @@
     if (status.isOk()) {
         if (ScopedAStatus callbackStatus = callCallback(callback, parcelableResults);
             !callbackStatus.isOk()) {
-            ALOGE("failed to call callback, error: %s, code: %d", status.getMessage(),
-                  status.getServiceSpecificError());
+            ALOGE("failed to call GetOrSetValueResults callback, client ID: %p, error: %s, "
+                  "exception: %d, service specific error: %d",
+                  callback->asBinder().get(), callbackStatus.getMessage(),
+                  callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
         }
         return;
     }
@@ -192,7 +196,7 @@
     return reinterpret_cast<const void*>(this);
 }
 
-Result<void> ConnectedClient::addRequests(const std::unordered_set<int64_t>& requestIds) {
+VhalResult<void> ConnectedClient::addRequests(const std::unordered_set<int64_t>& requestIds) {
     return mRequestPool->addRequests(id(), requestIds, getTimeoutCallback());
 }
 
@@ -296,8 +300,10 @@
     if (ScopedAStatus callbackStatus =
                 callback->onPropertyEvent(vehiclePropValues, sharedMemoryFileCount);
         !callbackStatus.isOk()) {
-        ALOGE("subscribe: failed to call callback, error: %s, code: %d", status.getMessage(),
-              status.getServiceSpecificError());
+        ALOGE("subscribe: failed to call UpdateValues callback, client ID: %p, error: %s, "
+              "exception: %d, service specific error: %d",
+              callback->asBinder().get(), callbackStatus.getMessage(),
+              callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
     }
 }
 
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index c0a66da..82f2c1b 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -78,12 +78,32 @@
     return str;
 }
 
+float getDefaultSampleRate(float sampleRate, float minSampleRate, float maxSampleRate) {
+    if (sampleRate < minSampleRate) {
+        return minSampleRate;
+    }
+    if (sampleRate > maxSampleRate) {
+        return maxSampleRate;
+    }
+    return sampleRate;
+}
+
 }  // namespace
 
+std::shared_ptr<SubscriptionClient> DefaultVehicleHal::SubscriptionClients::maybeAddClient(
+        const CallbackType& callback) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return getOrCreateClient(&mClients, callback, mPendingRequestPool);
+}
+
 std::shared_ptr<SubscriptionClient> DefaultVehicleHal::SubscriptionClients::getClient(
         const CallbackType& callback) {
     std::scoped_lock<std::mutex> lockGuard(mLock);
-    return getOrCreateClient(&mClients, callback, mPendingRequestPool);
+    const AIBinder* clientId = callback->asBinder().get();
+    if (mClients.find(clientId) == mClients.end()) {
+        return nullptr;
+    }
+    return mClients[clientId];
 }
 
 int64_t DefaultVehicleHal::SubscribeIdByClient::getId(const CallbackType& callback) {
@@ -115,7 +135,7 @@
     auto result = LargeParcelableBase::parcelableToStableLargeParcelable(vehiclePropConfigs);
     if (!result.ok()) {
         ALOGE("failed to convert configs to shared memory file, error: %s, code: %d",
-              getErrorMsg(result).c_str(), getIntErrorCode(result));
+              result.error().message().c_str(), static_cast<int>(result.error().code()));
         return;
     }
 
@@ -148,7 +168,8 @@
                 checkHealth(hardwareCopy, subscriptionManagerCopy);
             }));
 
-    mLinkToDeathImpl = std::make_unique<AIBinderLinkToDeathImpl>();
+    mBinderImpl = std::make_unique<AIBinderImpl>();
+    mOnBinderDiedUnlinkedHandlerThread = std::thread([this] { onBinderDiedUnlinkedHandler(); });
     mDeathRecipient = ScopedAIBinder_DeathRecipient(
             AIBinder_DeathRecipient_new(&DefaultVehicleHal::onBinderDied));
     AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(),
@@ -158,6 +179,10 @@
 DefaultVehicleHal::~DefaultVehicleHal() {
     // Delete the deathRecipient so that onBinderDied would not be called to reference 'this'.
     mDeathRecipient = ScopedAIBinder_DeathRecipient();
+    mBinderEvents.deactivate();
+    if (mOnBinderDiedUnlinkedHandlerThread.joinable()) {
+        mOnBinderDiedUnlinkedHandlerThread.join();
+    }
 }
 
 void DefaultVehicleHal::onPropertyChangeEvent(
@@ -189,36 +214,41 @@
     return (*clients)[clientId];
 }
 
-void DefaultVehicleHal::monitorBinderLifeCycle(const CallbackType& callback) {
-    AIBinder* clientId = callback->asBinder().get();
-    {
-        std::scoped_lock<std::mutex> lockGuard(mLock);
-        if (mOnBinderDiedContexts.find(clientId) != mOnBinderDiedContexts.end()) {
-            // Already registered.
-            return;
-        }
-    }
-
-    std::unique_ptr<OnBinderDiedContext> context = std::make_unique<OnBinderDiedContext>(
-            OnBinderDiedContext{.vhal = this, .clientId = clientId});
-    binder_status_t status = mLinkToDeathImpl->linkToDeath(clientId, mDeathRecipient.get(),
-                                                           static_cast<void*>(context.get()));
-    if (status == STATUS_OK) {
-        std::scoped_lock<std::mutex> lockGuard(mLock);
+bool DefaultVehicleHal::monitorBinderLifeCycleLocked(const AIBinder* clientId) {
+    OnBinderDiedContext* contextPtr = nullptr;
+    if (mOnBinderDiedContexts.find(clientId) != mOnBinderDiedContexts.end()) {
+        return mBinderImpl->isAlive(clientId);
+    } else {
+        std::unique_ptr<OnBinderDiedContext> context = std::make_unique<OnBinderDiedContext>(
+                OnBinderDiedContext{.vhal = this, .clientId = clientId});
+        // We know context must be alive when we use contextPtr because context would only
+        // be removed in OnBinderUnlinked, which must be called after OnBinderDied.
+        contextPtr = context.get();
         // Insert into a map to keep the context object alive.
         mOnBinderDiedContexts[clientId] = std::move(context);
-    } else {
-        ALOGE("failed to call linkToDeath on client binder, status: %d", static_cast<int>(status));
     }
+
+    // If this function fails, onBinderUnlinked would be called to remove the added context.
+    binder_status_t status = mBinderImpl->linkToDeath(
+            const_cast<AIBinder*>(clientId), mDeathRecipient.get(), static_cast<void*>(contextPtr));
+    if (status == STATUS_OK) {
+        return true;
+    }
+    ALOGE("failed to call linkToDeath on client binder, client may already died, status: %d",
+          static_cast<int>(status));
+    return false;
 }
 
 void DefaultVehicleHal::onBinderDied(void* cookie) {
     OnBinderDiedContext* context = reinterpret_cast<OnBinderDiedContext*>(cookie);
-    context->vhal->onBinderDiedWithContext(context->clientId);
+    // To be handled in mOnBinderDiedUnlinkedHandlerThread. We cannot handle the event in the same
+    // thread because we might be holding the mLock the handler requires.
+    context->vhal->mBinderEvents.push(BinderDiedUnlinkedEvent{true, context->clientId});
 }
 
 void DefaultVehicleHal::onBinderDiedWithContext(const AIBinder* clientId) {
     std::scoped_lock<std::mutex> lockGuard(mLock);
+    ALOGD("binder died, client ID: %p", clientId);
     mSetValuesClients.erase(clientId);
     mGetValuesClients.erase(clientId);
     mSubscriptionClients->removeClient(clientId);
@@ -226,16 +256,31 @@
 }
 
 void DefaultVehicleHal::onBinderUnlinked(void* cookie) {
-    // Delete the context associated with this cookie.
     OnBinderDiedContext* context = reinterpret_cast<OnBinderDiedContext*>(cookie);
-    context->vhal->onBinderUnlinkedWithContext(context->clientId);
+    // To be handled in mOnBinderDiedUnlinkedHandlerThread. We cannot handle the event in the same
+    // thread because we might be holding the mLock the handler requires.
+    context->vhal->mBinderEvents.push(BinderDiedUnlinkedEvent{false, context->clientId});
 }
 
 void DefaultVehicleHal::onBinderUnlinkedWithContext(const AIBinder* clientId) {
+    ALOGD("binder unlinked");
     std::scoped_lock<std::mutex> lockGuard(mLock);
+    // Delete the context associated with this cookie.
     mOnBinderDiedContexts.erase(clientId);
 }
 
+void DefaultVehicleHal::onBinderDiedUnlinkedHandler() {
+    while (mBinderEvents.waitForItems()) {
+        for (BinderDiedUnlinkedEvent& event : mBinderEvents.flush()) {
+            if (event.onBinderDied) {
+                onBinderDiedWithContext(event.clientId);
+            } else {
+                onBinderUnlinkedWithContext(event.clientId);
+            }
+        }
+    }
+}
+
 template std::shared_ptr<DefaultVehicleHal::GetValuesClient>
 DefaultVehicleHal::getOrCreateClient<DefaultVehicleHal::GetValuesClient>(
         std::unordered_map<const AIBinder*, std::shared_ptr<GetValuesClient>>* clients,
@@ -256,6 +301,10 @@
         const VehiclePropValue& value) {
     int64_t subscribeId = subscribeIdByClient->getId(callback);
     auto client = subscriptionClients->getClient(callback);
+    if (client == nullptr) {
+        ALOGW("subscribe[%" PRId64 "]: the client has died", subscribeId);
+        return;
+    }
     if (auto addRequestResult = client->addRequests({subscribeId}); !addRequestResult.ok()) {
         ALOGE("subscribe[%" PRId64 "]: too many pending requests, ignore the getValue request",
               subscribeId);
@@ -334,8 +383,6 @@
 
 ScopedAStatus DefaultVehicleHal::getValues(const CallbackType& callback,
                                            const GetValueRequests& requests) {
-    monitorBinderLifeCycle(callback);
-
     expected<LargeParcelableBase::BorrowedOwnedObject<GetValueRequests>, ScopedAStatus>
             deserializedResults = fromStableLargeParcelable(requests);
     if (!deserializedResults.ok()) {
@@ -377,9 +424,16 @@
 
     std::shared_ptr<GetValuesClient> client;
     {
-        std::scoped_lock<std::mutex> lockGuard(mLock);
+        // Lock to make sure onBinderDied would not be called concurrently.
+        std::scoped_lock lockGuard(mLock);
+        if (!monitorBinderLifeCycleLocked(callback->asBinder().get())) {
+            return ScopedAStatus::fromExceptionCodeWithMessage(EX_TRANSACTION_FAILED,
+                                                               "client died");
+        }
+
         client = getOrCreateClient(&mGetValuesClients, callback, mPendingRequestPool);
     }
+
     // Register the pending hardware requests and also check for duplicate request Ids.
     if (auto addRequestResult = client->addRequests(hardwareRequestIds); !addRequestResult.ok()) {
         ALOGE("getValues[%s]: failed to add pending requests, error: %s",
@@ -412,8 +466,6 @@
 
 ScopedAStatus DefaultVehicleHal::setValues(const CallbackType& callback,
                                            const SetValueRequests& requests) {
-    monitorBinderLifeCycle(callback);
-
     expected<LargeParcelableBase::BorrowedOwnedObject<SetValueRequests>, ScopedAStatus>
             deserializedResults = fromStableLargeParcelable(requests);
     if (!deserializedResults.ok()) {
@@ -465,7 +517,12 @@
 
     std::shared_ptr<SetValuesClient> client;
     {
-        std::scoped_lock<std::mutex> lockGuard(mLock);
+        // Lock to make sure onBinderDied would not be called concurrently.
+        std::scoped_lock lockGuard(mLock);
+        if (!monitorBinderLifeCycleLocked(callback->asBinder().get())) {
+            return ScopedAStatus::fromExceptionCodeWithMessage(EX_TRANSACTION_FAILED,
+                                                               "client died");
+        }
         client = getOrCreateClient(&mSetValuesClients, callback, mPendingRequestPool);
     }
 
@@ -473,7 +530,7 @@
     if (auto addRequestResult = client->addRequests(hardwareRequestIds); !addRequestResult.ok()) {
         ALOGE("setValues[%s], failed to add pending requests, error: %s",
               toString(hardwareRequestIds).c_str(), getErrorMsg(addRequestResult).c_str());
-        return toScopedAStatus(addRequestResult, StatusCode::INVALID_ARG);
+        return toScopedAStatus(addRequestResult);
     }
 
     if (!failedResults.empty()) {
@@ -534,30 +591,34 @@
     for (int32_t prop : props) {
         if (mConfigsByPropId.find(prop) != mConfigsByPropId.end()) {
             configs.push_back(mConfigsByPropId[prop]);
+        } else {
+            return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                    toInt(StatusCode::INVALID_ARG),
+                    StringPrintf("no config for property, ID: %" PRId32, prop).c_str());
         }
     }
     return vectorToStableLargeParcelable(std::move(configs), output);
 }
 
-Result<void> DefaultVehicleHal::checkSubscribeOptions(
+VhalResult<void> DefaultVehicleHal::checkSubscribeOptions(
         const std::vector<SubscribeOptions>& options) {
     for (const auto& option : options) {
         int32_t propId = option.propId;
         if (mConfigsByPropId.find(propId) == mConfigsByPropId.end()) {
-            return Error(toInt(StatusCode::INVALID_ARG))
+            return StatusError(StatusCode::INVALID_ARG)
                    << StringPrintf("no config for property, ID: %" PRId32, propId);
         }
         const VehiclePropConfig& config = mConfigsByPropId[propId];
 
         if (config.changeMode != VehiclePropertyChangeMode::ON_CHANGE &&
             config.changeMode != VehiclePropertyChangeMode::CONTINUOUS) {
-            return Error(toInt(StatusCode::INVALID_ARG))
+            return StatusError(StatusCode::INVALID_ARG)
                    << "only support subscribing to ON_CHANGE or CONTINUOUS property";
         }
 
         if (config.access != VehiclePropertyAccess::READ &&
             config.access != VehiclePropertyAccess::READ_WRITE) {
-            return Error(toInt(StatusCode::ACCESS_DENIED))
+            return StatusError(StatusCode::ACCESS_DENIED)
                    << StringPrintf("Property %" PRId32 " has no read access", propId);
         }
 
@@ -566,12 +627,13 @@
             float minSampleRate = config.minSampleRate;
             float maxSampleRate = config.maxSampleRate;
             if (sampleRate < minSampleRate || sampleRate > maxSampleRate) {
-                return Error(toInt(StatusCode::INVALID_ARG))
-                       << StringPrintf("sample rate: %f out of range, must be within %f and %f",
-                                       sampleRate, minSampleRate, maxSampleRate);
+                float defaultRate = getDefaultSampleRate(sampleRate, minSampleRate, maxSampleRate);
+                ALOGW("sample rate: %f out of range, must be within %f and %f, set to %f",
+                      sampleRate, minSampleRate, maxSampleRate, defaultRate);
+                sampleRate = defaultRate;
             }
             if (!SubscriptionManager::checkSampleRate(sampleRate)) {
-                return Error(toInt(StatusCode::INVALID_ARG))
+                return StatusError(StatusCode::INVALID_ARG)
                        << "invalid sample rate: " << sampleRate;
             }
         }
@@ -583,7 +645,7 @@
         // Non-global property.
         for (int32_t areaId : option.areaIds) {
             if (auto areaConfig = getAreaConfig(propId, areaId, config); areaConfig == nullptr) {
-                return Error(toInt(StatusCode::INVALID_ARG))
+                return StatusError(StatusCode::INVALID_ARG)
                        << StringPrintf("invalid area ID: %" PRId32 " for prop ID: %" PRId32
                                        ", not listed in config",
                                        areaId, propId);
@@ -596,8 +658,6 @@
 ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType& callback,
                                            const std::vector<SubscribeOptions>& options,
                                            [[maybe_unused]] int32_t maxSharedMemoryFileCount) {
-    monitorBinderLifeCycle(callback);
-
     // TODO(b/205189110): Use shared memory file count.
     if (auto result = checkSubscribeOptions(options); !result.ok()) {
         ALOGE("subscribe: invalid subscribe options: %s", getErrorMsg(result).c_str());
@@ -624,19 +684,34 @@
         }
 
         if (config.changeMode == VehiclePropertyChangeMode::CONTINUOUS) {
+            optionCopy.sampleRate = getDefaultSampleRate(
+                    optionCopy.sampleRate, config.minSampleRate, config.maxSampleRate);
             continuousSubscriptions.push_back(std::move(optionCopy));
         } else {
             onChangeSubscriptions.push_back(std::move(optionCopy));
         }
     }
-    // Since we have already check the sample rates, the following functions must succeed.
-    if (!onChangeSubscriptions.empty()) {
-        mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
-                                        /*isContinuousProperty=*/false);
-    }
-    if (!continuousSubscriptions.empty()) {
-        mSubscriptionManager->subscribe(callback, continuousSubscriptions,
-                                        /*isContinuousProperty=*/true);
+
+    {
+        // Lock to make sure onBinderDied would not be called concurrently.
+        std::scoped_lock lockGuard(mLock);
+        if (!monitorBinderLifeCycleLocked(callback->asBinder().get())) {
+            return ScopedAStatus::fromExceptionCodeWithMessage(EX_TRANSACTION_FAILED,
+                                                               "client died");
+        }
+
+        // Create a new SubscriptionClient if there isn't an existing one.
+        mSubscriptionClients->maybeAddClient(callback);
+
+        // Since we have already check the sample rates, the following functions must succeed.
+        if (!onChangeSubscriptions.empty()) {
+            mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
+                                            /*isContinuousProperty=*/false);
+        }
+        if (!continuousSubscriptions.empty()) {
+            mSubscriptionManager->subscribe(callback, continuousSubscriptions,
+                                            /*isContinuousProperty=*/true);
+        }
     }
     return ScopedAStatus::ok();
 }
@@ -656,33 +731,33 @@
     return mVehicleHardware.get();
 }
 
-Result<void> DefaultVehicleHal::checkWritePermission(const VehiclePropValue& value) const {
+VhalResult<void> DefaultVehicleHal::checkWritePermission(const VehiclePropValue& value) const {
     int32_t propId = value.prop;
     auto result = getConfig(propId);
     if (!result.ok()) {
-        return Error(toInt(StatusCode::INVALID_ARG)) << getErrorMsg(result);
+        return StatusError(StatusCode::INVALID_ARG) << getErrorMsg(result);
     }
     const VehiclePropConfig* config = result.value();
 
     if (config->access != VehiclePropertyAccess::WRITE &&
         config->access != VehiclePropertyAccess::READ_WRITE) {
-        return Error(toInt(StatusCode::ACCESS_DENIED))
+        return StatusError(StatusCode::ACCESS_DENIED)
                << StringPrintf("Property %" PRId32 " has no write access", propId);
     }
     return {};
 }
 
-Result<void> DefaultVehicleHal::checkReadPermission(const VehiclePropValue& value) const {
+VhalResult<void> DefaultVehicleHal::checkReadPermission(const VehiclePropValue& value) const {
     int32_t propId = value.prop;
     auto result = getConfig(propId);
     if (!result.ok()) {
-        return Error(toInt(StatusCode::INVALID_ARG)) << getErrorMsg(result);
+        return StatusError(StatusCode::INVALID_ARG) << getErrorMsg(result);
     }
     const VehiclePropConfig* config = result.value();
 
     if (config->access != VehiclePropertyAccess::READ &&
         config->access != VehiclePropertyAccess::READ_WRITE) {
-        return Error(toInt(StatusCode::ACCESS_DENIED))
+        return StatusError(StatusCode::ACCESS_DENIED)
                << StringPrintf("Property %" PRId32 " has no read access", propId);
     }
     return {};
@@ -711,13 +786,18 @@
     return;
 }
 
-binder_status_t DefaultVehicleHal::AIBinderLinkToDeathImpl::linkToDeath(
-        AIBinder* binder, AIBinder_DeathRecipient* recipient, void* cookie) {
+binder_status_t DefaultVehicleHal::AIBinderImpl::linkToDeath(AIBinder* binder,
+                                                             AIBinder_DeathRecipient* recipient,
+                                                             void* cookie) {
     return AIBinder_linkToDeath(binder, recipient, cookie);
 }
 
-void DefaultVehicleHal::setLinkToDeathImpl(std::unique_ptr<ILinkToDeath> impl) {
-    mLinkToDeathImpl = std::move(impl);
+bool DefaultVehicleHal::AIBinderImpl::isAlive(const AIBinder* binder) {
+    return AIBinder_isAlive(binder);
+}
+
+void DefaultVehicleHal::setBinderImpl(std::unique_ptr<IBinder> impl) {
+    mBinderImpl = std::move(impl);
 }
 
 bool DefaultVehicleHal::checkDumpPermission() {
diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index 178498b..49f5b7e 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
@@ -197,14 +197,6 @@
                             },
             },
             {
-                    .name = "sample_rate_out_of_range",
-                    .option =
-                            {
-                                    .propId = GLOBAL_CONTINUOUS_PROP,
-                                    .sampleRate = 1000.0,
-                            },
-            },
-            {
                     .name = "static_property",
                     .option =
                             {
@@ -332,7 +324,9 @@
         mCallbackClient = IVehicleCallback::fromBinder(mBinder);
 
         // Set the linkToDeath to a fake implementation that always returns OK.
-        setTestLinkToDeathImpl();
+        auto binderImpl = std::make_unique<TestBinderImpl>();
+        mBinderImpl = binderImpl.get();
+        mVhal->setBinderImpl(std::move(binderImpl));
     }
 
     void TearDown() override {
@@ -350,10 +344,6 @@
 
     void setTimeout(int64_t timeoutInNano) { mVhal->setTimeout(timeoutInNano); }
 
-    void setTestLinkToDeathImpl() {
-        mVhal->setLinkToDeathImpl(std::make_unique<TestLinkToDeathImpl>());
-    }
-
     size_t countPendingRequests() { return mVhal->mPendingRequestPool->countPendingRequests(); }
 
     size_t countClients() {
@@ -380,6 +370,8 @@
 
     bool hasNoSubscriptions() { return mVhal->mSubscriptionManager->isEmpty(); }
 
+    void setBinderAlive(bool isAlive) { mBinderImpl->setAlive(isAlive); };
+
     static Result<void> getValuesTestCases(size_t size, GetValueRequests& requests,
                                            std::vector<GetValueResult>& expectedResults,
                                            std::vector<GetValueRequest>& expectedHardwareRequests) {
@@ -452,19 +444,31 @@
     }
 
   private:
+    class TestBinderImpl final : public DefaultVehicleHal::IBinder {
+      public:
+        binder_status_t linkToDeath(AIBinder*, AIBinder_DeathRecipient*, void*) override {
+            if (mIsAlive) {
+                return STATUS_OK;
+            } else {
+                return STATUS_FAILED_TRANSACTION;
+            }
+        }
+
+        bool isAlive(const AIBinder*) override { return mIsAlive; }
+
+        void setAlive(bool isAlive) { mIsAlive = isAlive; }
+
+      private:
+        bool mIsAlive = true;
+    };
+
     std::shared_ptr<DefaultVehicleHal> mVhal;
     std::shared_ptr<IVehicle> mVhalClient;
     MockVehicleHardware* mHardwarePtr;
     std::shared_ptr<MockVehicleCallback> mCallback;
     std::shared_ptr<IVehicleCallback> mCallbackClient;
     SpAIBinder mBinder;
-
-    class TestLinkToDeathImpl final : public DefaultVehicleHal::ILinkToDeath {
-      public:
-        binder_status_t linkToDeath(AIBinder*, AIBinder_DeathRecipient*, void*) override {
-            return STATUS_OK;
-        }
-    };
+    TestBinderImpl* mBinderImpl;
 };
 
 TEST_F(DefaultVehicleHalTest, testGetAllPropConfigsSmall) {
@@ -514,6 +518,50 @@
     ASSERT_EQ(result.value().getObject()->payloads, testConfigs);
 }
 
+TEST_F(DefaultVehicleHalTest, testGetPropConfigs) {
+    auto testConfigs = std::vector<VehiclePropConfig>({
+            VehiclePropConfig{
+                    .prop = 1,
+            },
+            VehiclePropConfig{
+                    .prop = 2,
+            },
+    });
+
+    auto hardware = std::make_unique<MockVehicleHardware>();
+    hardware->setPropertyConfigs(testConfigs);
+    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
+    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+
+    VehiclePropConfigs output;
+    auto status = client->getPropConfigs(std::vector<int32_t>({1, 2}), &output);
+
+    ASSERT_TRUE(status.isOk()) << "getPropConfigs failed: " << status.getMessage();
+    ASSERT_EQ(output.payloads, testConfigs);
+}
+
+TEST_F(DefaultVehicleHalTest, testGetPropConfigsInvalidArg) {
+    auto testConfigs = std::vector<VehiclePropConfig>({
+            VehiclePropConfig{
+                    .prop = 1,
+            },
+            VehiclePropConfig{
+                    .prop = 2,
+            },
+    });
+
+    auto hardware = std::make_unique<MockVehicleHardware>();
+    hardware->setPropertyConfigs(testConfigs);
+    auto vhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
+    std::shared_ptr<IVehicle> client = IVehicle::fromBinder(vhal->asBinder());
+
+    VehiclePropConfigs output;
+    auto status = client->getPropConfigs(std::vector<int32_t>({1, 2, 3}), &output);
+
+    ASSERT_FALSE(status.isOk()) << "getPropConfigs must fail with invalid prop ID";
+    ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
+}
+
 TEST_F(DefaultVehicleHalTest, testGetValuesSmall) {
     GetValueRequests requests;
     std::vector<GetValueResult> expectedResults;
@@ -543,7 +591,6 @@
 
     ASSERT_TRUE(getValuesTestCases(5000, requests, expectedResults, expectedHardwareRequests).ok())
             << "requests to hardware mismatch";
-    ;
 
     getHardware()->addGetValueResponses(expectedResults);
 
@@ -762,6 +809,51 @@
     ASSERT_FALSE(status.isOk()) << "duplicate request properties in one request must fail";
 }
 
+TEST_F(DefaultVehicleHalTest, testGetValuesNewClientDied) {
+    GetValueRequests requests;
+    std::vector<GetValueResult> expectedResults;
+    std::vector<GetValueRequest> expectedHardwareRequests;
+
+    ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+    getHardware()->addGetValueResponses(expectedResults);
+
+    setBinderAlive(false);
+
+    auto status = getClient()->getValues(getCallbackClient(), requests);
+
+    ASSERT_FALSE(status.isOk()) << "getValues must fail if client died";
+    ASSERT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
+    EXPECT_EQ(countClients(), static_cast<size_t>(0))
+            << "No client should be created if the client binder died";
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesExistingClientDied) {
+    GetValueRequests requests;
+    std::vector<GetValueResult> expectedResults;
+    std::vector<GetValueRequest> expectedHardwareRequests;
+
+    ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+    getHardware()->addGetValueResponses(expectedResults);
+
+    // Try a normal getValue request to cache a GetValueClient first.
+    auto status = getClient()->getValues(getCallbackClient(), requests);
+
+    ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
+    EXPECT_EQ(countClients(), static_cast<size_t>(1));
+
+    // The client binder died before onBinderUnlinked clean up the GetValueClient.
+    setBinderAlive(false);
+
+    status = getClient()->getValues(getCallbackClient(), requests);
+
+    ASSERT_FALSE(status.isOk()) << "getValues must fail if client died";
+    ASSERT_EQ(status.getExceptionCode(), EX_TRANSACTION_FAILED);
+    // The client count should still be 1 but onBinderUnlinked will remove this later.
+    EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
 TEST_F(DefaultVehicleHalTest, testSetValuesSmall) {
     SetValueRequests requests;
     std::vector<SetValueResult> expectedResults;
@@ -1067,7 +1159,8 @@
             << "results mismatch, expect on change event for the updated value";
     ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
             << "more results than expected";
-    EXPECT_EQ(countClients(), static_cast<size_t>(1));
+    EXPECT_EQ(countClients(), static_cast<size_t>(2))
+            << "expect 2 clients, 1 subscribe client and 1 setvalue client";
 }
 
 TEST_F(DefaultVehicleHalTest, testSubscribeGlobalOnchangeUnrelatedEventIgnored) {
@@ -1259,6 +1352,51 @@
     EXPECT_EQ(countClients(), static_cast<size_t>(1));
 }
 
+TEST_F(DefaultVehicleHalTest, testSubscribeGlobalContinuousRateOutOfRange) {
+    VehiclePropValue testValue{
+            .prop = GLOBAL_CONTINUOUS_PROP,
+            .value.int32Values = {0},
+    };
+    // Set responses for all the hardware getValues requests.
+    getHardware()->setGetValueResponder(
+            [](std::shared_ptr<const IVehicleHardware::GetValuesCallback> callback,
+               const std::vector<GetValueRequest>& requests) {
+                std::vector<GetValueResult> results;
+                for (auto& request : requests) {
+                    VehiclePropValue prop = request.prop;
+                    prop.value.int32Values = {0};
+                    results.push_back({
+                            .requestId = request.requestId,
+                            .status = StatusCode::OK,
+                            .prop = prop,
+                    });
+                }
+                (*callback)(results);
+                return StatusCode::OK;
+            });
+
+    // The maxSampleRate is 100, so the sample rate should be the default max 100.
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = GLOBAL_CONTINUOUS_PROP,
+                    .sampleRate = 1000.0,
+            },
+    };
+
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+    // Sleep for 1s, which should generate ~100 events.
+    std::this_thread::sleep_for(std::chrono::seconds(1));
+
+    size_t eventCount = getCallback()->countOnPropertyEventResults();
+    ASSERT_GE(eventCount, 50u) << "expect at least 50 events to be generated";
+    ASSERT_LE(eventCount, 150u) << "expect no more than 150 events to be generated";
+
+    EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
 TEST_F(DefaultVehicleHalTest, testSubscribeAreaContinuous) {
     // Set responses for all the hardware getValues requests.
     getHardware()->setGetValueResponder(
@@ -1537,12 +1675,28 @@
 
     onBinderDied(context);
 
+    // Sleep for 100ms between checks.
+    int64_t sleep = 100;
+    // Timeout: 10s.
+    int64_t timeout = 10'000'000'000;
+    int64_t stopTime = elapsedRealtimeNano() + timeout;
+    // Wait until the onBinderDied event is handled.
+    while (countClients() != 0u && elapsedRealtimeNano() <= stopTime) {
+        std::this_thread::sleep_for(std::chrono::milliseconds(sleep));
+    }
+
     ASSERT_EQ(countClients(), static_cast<size_t>(0))
             << "expect all clients to be removed when binder died";
     ASSERT_TRUE(hasNoSubscriptions()) << "expect no subscriptions when binder died";
 
     onBinderUnlinked(context);
 
+    stopTime = elapsedRealtimeNano() + timeout;
+    // Wait until the onBinderUnlinked event is handled.
+    while (countOnBinderDiedContexts() != 0u && elapsedRealtimeNano() <= stopTime) {
+        std::this_thread::sleep_for(std::chrono::milliseconds(sleep));
+    }
+
     ASSERT_EQ(countOnBinderDiedContexts(), static_cast<size_t>(0))
             << "expect OnBinderDied context to be deleted when binder is unlinked";
 }
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
index 5e3e03c..0e46357 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
@@ -82,6 +82,11 @@
     return pop(mOnPropertyEventResults);
 }
 
+size_t MockVehicleCallback::countOnPropertyEventResults() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mOnPropertyEventResults.size();
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
index 03bfd5b..0faaa1f 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
@@ -62,6 +62,7 @@
     nextSetValueResults();
     std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropValues>
     nextOnPropertyEventResults();
+    size_t countOnPropertyEventResults();
 
   private:
     std::mutex mLock;
diff --git a/automotive/vehicle/aidl/impl/vhal/vhal-default-service.xml b/automotive/vehicle/aidl/impl/vhal/vhal-default-service.xml
index 8d237b8..4d587ee 100644
--- a/automotive/vehicle/aidl/impl/vhal/vhal-default-service.xml
+++ b/automotive/vehicle/aidl/impl/vhal/vhal-default-service.xml
@@ -1,11 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.automotive.vehicle</name>
-        <transport>hwbinder</transport>
         <version>1</version>
-        <interface>
-            <name>IVehicle</name>
-            <instance>default</instance>
-        </interface>
+        <fqname>IVehicle/default</fqname>
     </hal>
 </manifest>
diff --git a/automotive/vehicle/vts/Android.bp b/automotive/vehicle/vts/Android.bp
new file mode 100644
index 0000000..c8276d7
--- /dev/null
+++ b/automotive/vehicle/vts/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_test {
+    name: "VtsHalAutomotiveVehicle_TargetTest",
+    srcs: [
+        "src/*.cpp",
+    ],
+    static_libs: [
+        "libgtest",
+        "libvhalclient",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libvndksupport",
+    ],
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+        "vhalclient_defaults",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    require_root: true,
+}
diff --git a/automotive/vehicle/2.0/vts/functional/OWNERS b/automotive/vehicle/vts/OWNERS
similarity index 71%
rename from automotive/vehicle/2.0/vts/functional/OWNERS
rename to automotive/vehicle/vts/OWNERS
index 8a0f2af..c93a843 100644
--- a/automotive/vehicle/2.0/vts/functional/OWNERS
+++ b/automotive/vehicle/vts/OWNERS
@@ -1,2 +1,3 @@
 # Bug component: 533426
+shanyu@google.com
 kwangsudo@google.com
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
new file mode 100644
index 0000000..c33f3e9
--- /dev/null
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalAutomotiveVehicle"
+
+#include <IVhalClient.h>
+#include <VehicleHalTypes.h>
+#include <VehicleUtils.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/automotive/vehicle/IVehicle.h>
+#include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <inttypes.h>
+#include <utils/Log.h>
+
+#include <chrono>
+#include <mutex>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+using ::aidl::android::hardware::automotive::vehicle::IVehicle;
+using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
+using ::android::getAidlHalInstanceNames;
+using ::android::base::ScopedLockAssertion;
+using ::android::base::StringPrintf;
+using ::android::frameworks::automotive::vhal::HalPropError;
+using ::android::frameworks::automotive::vhal::IHalPropConfig;
+using ::android::frameworks::automotive::vhal::IHalPropValue;
+using ::android::frameworks::automotive::vhal::ISubscriptionCallback;
+using ::android::frameworks::automotive::vhal::IVhalClient;
+using ::android::hardware::getAllHalInstanceNames;
+using ::android::hardware::Sanitize;
+using ::android::hardware::automotive::vehicle::toInt;
+
+constexpr int32_t kInvalidProp = 0x31600207;
+
+struct ServiceDescriptor {
+    std::string name;
+    bool isAidlService;
+};
+
+class VtsVehicleCallback final : public ISubscriptionCallback {
+  private:
+    std::mutex mLock;
+    std::unordered_map<int32_t, size_t> mEventsCount GUARDED_BY(mLock);
+    std::condition_variable mEventCond;
+
+  public:
+    void onPropertyEvent(const std::vector<std::unique_ptr<IHalPropValue>>& values) override {
+        {
+            std::lock_guard<std::mutex> lockGuard(mLock);
+            for (auto& value : values) {
+                mEventsCount[value->getPropId()] += 1;
+            }
+        }
+        mEventCond.notify_one();
+    }
+
+    void onPropertySetError([[maybe_unused]] const std::vector<HalPropError>& errors) override {
+        // Do nothing.
+    }
+
+    template <class Rep, class Period>
+    bool waitForExpectedEvents(int32_t propId, size_t expectedEvents,
+                               const std::chrono::duration<Rep, Period>& timeout) {
+        std::unique_lock<std::mutex> uniqueLock(mLock);
+        return mEventCond.wait_for(uniqueLock, timeout, [this, propId, expectedEvents] {
+            ScopedLockAssertion lockAssertion(mLock);
+            return mEventsCount[propId] >= expectedEvents;
+        });
+    }
+
+    void reset() {
+        std::lock_guard<std::mutex> lockGuard(mLock);
+        mEventsCount.clear();
+    }
+};
+
+class VtsHalAutomotiveVehicleTargetTest : public testing::TestWithParam<ServiceDescriptor> {
+  public:
+    virtual void SetUp() override {
+        auto descriptor = GetParam();
+        if (descriptor.isAidlService) {
+            mVhalClient = IVhalClient::tryCreateAidlClient(descriptor.name.c_str());
+        } else {
+            mVhalClient = IVhalClient::tryCreateHidlClient(descriptor.name.c_str());
+        }
+
+        ASSERT_NE(mVhalClient, nullptr) << "Failed to connect to VHAL";
+
+        mCallback = std::make_shared<VtsVehicleCallback>();
+    }
+
+    static bool isBooleanGlobalProp(int32_t property) {
+        return (property & toInt(VehiclePropertyType::MASK)) ==
+                       toInt(VehiclePropertyType::BOOLEAN) &&
+               (property & toInt(VehicleArea::MASK)) == toInt(VehicleArea::GLOBAL);
+    }
+
+  protected:
+    std::shared_ptr<IVhalClient> mVhalClient;
+    std::shared_ptr<VtsVehicleCallback> mCallback;
+};
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, useAidlBackend) {
+    if (!mVhalClient->isAidlVhal()) {
+        GTEST_SKIP() << "AIDL backend is not available, HIDL backend is used instead";
+    }
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, useHidlBackend) {
+    if (mVhalClient->isAidlVhal()) {
+        GTEST_SKIP() << "AIDL backend is available, HIDL backend is not used";
+    }
+}
+
+// Test getAllPropConfig() returns at least 4 property configs.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, getAllPropConfigs) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::getAllPropConfigs");
+
+    auto result = mVhalClient->getAllPropConfigs();
+
+    ASSERT_TRUE(result.ok()) << "Failed to get all property configs, error: "
+                             << result.error().message();
+    ASSERT_GE(result.value().size(), 4u) << StringPrintf(
+            "Expect to get at least 4 property configs, got %zu", result.value().size());
+}
+
+// Test getPropConfigs() can query all properties listed in CDD.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, getRequiredPropConfigs) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::getRequiredPropConfigs");
+
+    // Check the properties listed in CDD
+    std::vector<int32_t> properties = {
+            toInt(VehicleProperty::GEAR_SELECTION), toInt(VehicleProperty::NIGHT_MODE),
+            toInt(VehicleProperty::PARKING_BRAKE_ON), toInt(VehicleProperty::PERF_VEHICLE_SPEED)};
+
+    auto result = mVhalClient->getPropConfigs(properties);
+
+    ASSERT_TRUE(result.ok()) << "Failed to get required property config, error: "
+                             << result.error().message();
+    ASSERT_EQ(result.value().size(), 4u)
+            << StringPrintf("Expect to get exactly 4 configs, got %zu", result.value().size());
+}
+
+// Test getPropConfig() with an invalid propertyId returns an error code.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, getPropConfigsWithInvalidProp) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::getPropConfigsWithInvalidProp");
+
+    auto result = mVhalClient->getPropConfigs({kInvalidProp});
+
+    ASSERT_FALSE(result.ok()) << StringPrintf(
+            "Expect failure to get prop configs for invalid prop: %" PRId32, kInvalidProp);
+    ASSERT_NE(result.error().message(), "") << "Expect error message not to be empty";
+}
+
+// Test get() return current value for properties.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, get) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::get");
+
+    int32_t propId = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
+    auto result = mVhalClient->getValueSync(*mVhalClient->createHalPropValue(propId));
+
+    ASSERT_TRUE(result.ok()) << StringPrintf("Failed to get value for property: %" PRId32
+                                             ", error: %s",
+                                             propId, result.error().message().c_str());
+    ASSERT_NE(result.value(), nullptr) << "Result value must not be null";
+}
+
+// Test get() with an invalid propertyId return an error codes.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, getInvalidProp) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::getInvalidProp");
+
+    auto result = mVhalClient->getValueSync(*mVhalClient->createHalPropValue(kInvalidProp));
+
+    ASSERT_FALSE(result.ok()) << StringPrintf(
+            "Expect failure to get property for invalid prop: %" PRId32, kInvalidProp);
+}
+
+// Test set() on read_write properties.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, setProp) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::setProp");
+
+    // skip hvac related properties
+    std::unordered_set<int32_t> hvacProps = {toInt(VehicleProperty::HVAC_DEFROSTER),
+                                             toInt(VehicleProperty::HVAC_AC_ON),
+                                             toInt(VehicleProperty::HVAC_MAX_AC_ON),
+                                             toInt(VehicleProperty::HVAC_MAX_DEFROST_ON),
+                                             toInt(VehicleProperty::HVAC_RECIRC_ON),
+                                             toInt(VehicleProperty::HVAC_DUAL_ON),
+                                             toInt(VehicleProperty::HVAC_AUTO_ON),
+                                             toInt(VehicleProperty::HVAC_POWER_ON),
+                                             toInt(VehicleProperty::HVAC_AUTO_RECIRC_ON),
+                                             toInt(VehicleProperty::HVAC_ELECTRIC_DEFROSTER_ON)};
+    auto result = mVhalClient->getAllPropConfigs();
+    ASSERT_TRUE(result.ok());
+
+    for (const auto& cfgPtr : result.value()) {
+        const IHalPropConfig& cfg = *cfgPtr;
+        int32_t propId = cfg.getPropId();
+        // test on boolean and writable property
+        if (cfg.getAccess() == toInt(VehiclePropertyAccess::READ_WRITE) &&
+            isBooleanGlobalProp(propId) && !hvacProps.count(propId)) {
+            auto propToGet = mVhalClient->createHalPropValue(propId);
+            auto getValueResult = mVhalClient->getValueSync(*propToGet);
+
+            ASSERT_TRUE(getValueResult.ok())
+                    << StringPrintf("Failed to get value for property: %" PRId32 ", error: %s",
+                                    propId, getValueResult.error().message().c_str());
+            ASSERT_NE(getValueResult.value(), nullptr)
+                    << StringPrintf("Result value must not be null for property: %" PRId32, propId);
+
+            const IHalPropValue& value = *getValueResult.value();
+            size_t intValueSize = value.getInt32Values().size();
+            ASSERT_EQ(intValueSize, 1u) << StringPrintf(
+                    "Expect exactly 1 int value for boolean property: %" PRId32 ", got %zu", propId,
+                    intValueSize);
+
+            int setValue = value.getInt32Values()[0] == 1 ? 0 : 1;
+            auto propToSet = mVhalClient->createHalPropValue(propId);
+            propToSet->setInt32Values({setValue});
+            auto setValueResult = mVhalClient->setValueSync(*propToSet);
+
+            ASSERT_TRUE(setValueResult.ok())
+                    << StringPrintf("Failed to set value for property: %" PRId32 ", error: %s",
+                                    propId, setValueResult.error().message().c_str());
+
+            // check set success
+            getValueResult = mVhalClient->getValueSync(*propToGet);
+            ASSERT_TRUE(getValueResult.ok())
+                    << StringPrintf("Failed to get value for property: %" PRId32 ", error: %s",
+                                    propId, getValueResult.error().message().c_str());
+            ASSERT_NE(getValueResult.value(), nullptr)
+                    << StringPrintf("Result value must not be null for property: %" PRId32, propId);
+            ASSERT_EQ(getValueResult.value()->getInt32Values(), std::vector<int32_t>({setValue}))
+                    << StringPrintf("Boolean value not updated after set for property: %" PRId32,
+                                    propId);
+        }
+    }
+}
+
+// Test set() on an read_only property.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, setNotWritableProp) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::setNotWritableProp");
+
+    int32_t propId = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
+    auto getValueResult = mVhalClient->getValueSync(*mVhalClient->createHalPropValue(propId));
+    ASSERT_TRUE(getValueResult.ok())
+            << StringPrintf("Failed to get value for property: %" PRId32 ", error: %s", propId,
+                            getValueResult.error().message().c_str());
+
+    auto setValueResult = mVhalClient->setValueSync(*getValueResult.value());
+
+    ASSERT_FALSE(setValueResult.ok()) << "Expect set a read-only value to fail";
+    ASSERT_EQ(setValueResult.error().code(), StatusCode::ACCESS_DENIED);
+}
+
+// Test subscribe() and unsubscribe().
+TEST_P(VtsHalAutomotiveVehicleTargetTest, subscribeAndUnsubscribe) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::subscribeAndUnsubscribe");
+
+    int32_t propId = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
+
+    std::vector<SubscribeOptions> options = {
+            SubscribeOptions{.propId = propId, .sampleRate = 10.0}};
+
+    auto client = mVhalClient->getSubscriptionClient(mCallback);
+    ASSERT_NE(client, nullptr) << "Failed to get subscription client";
+
+    auto result = client->subscribe(options);
+
+    ASSERT_TRUE(result.ok()) << StringPrintf("Failed to subscribe to property: %" PRId32
+                                             ", error: %s",
+                                             propId, result.error().message().c_str());
+    ASSERT_TRUE(mCallback->waitForExpectedEvents(propId, 10, std::chrono::seconds(10)))
+            << "Didn't get enough events for subscription";
+
+    result = client->unsubscribe({propId});
+    ASSERT_TRUE(result.ok()) << StringPrintf("Failed to unsubscribe to property: %" PRId32
+                                             ", error: %s",
+                                             propId, result.error().message().c_str());
+
+    mCallback->reset();
+    ASSERT_FALSE(mCallback->waitForExpectedEvents(propId, 10, std::chrono::seconds(1)))
+            << "Expect not to get events after unsubscription";
+}
+
+// Test subscribe() with an invalid property.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, subscribeInvalidProp) {
+    ALOGD("VtsHalAutomotiveVehicleTargetTest::subscribeInvalidProp");
+
+    std::vector<SubscribeOptions> options = {
+            SubscribeOptions{.propId = kInvalidProp, .sampleRate = 10.0}};
+
+    auto client = mVhalClient->getSubscriptionClient(mCallback);
+    ASSERT_NE(client, nullptr) << "Failed to get subscription client";
+
+    auto result = client->subscribe(options);
+
+    ASSERT_FALSE(result.ok()) << StringPrintf("Expect subscribing to property: %" PRId32 " to fail",
+                                              kInvalidProp);
+}
+
+std::vector<ServiceDescriptor> getDescriptors() {
+    std::vector<ServiceDescriptor> descriptors;
+    for (std::string name : getAidlHalInstanceNames(IVehicle::descriptor)) {
+        descriptors.push_back({
+                .name = name,
+                .isAidlService = true,
+        });
+    }
+    for (std::string name : getAllHalInstanceNames(IVehicle::descriptor)) {
+        descriptors.push_back({
+                .name = name,
+                .isAidlService = false,
+        });
+    }
+    return descriptors;
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VtsHalAutomotiveVehicleTargetTest);
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, VtsHalAutomotiveVehicleTargetTest,
+                         testing::ValuesIn(getDescriptors()),
+                         [](const testing::TestParamInfo<ServiceDescriptor>& info) {
+                             std::string name = "";
+                             if (info.param.isAidlService) {
+                                 name += "aidl_";
+                             } else {
+                                 name += "hidl_";
+                             }
+                             name += info.param.name;
+                             return Sanitize(name);
+                         });
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    return RUN_ALL_TESTS();
+}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl
index 4d7e59e..65c589f 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl
@@ -46,6 +46,10 @@
      * vold_prepare_subdirs.cpp). Implementations may store additional user-specific data, such as
      * embeddings or templates, in StrongBox.
      *
+     * During create session it is expected that the HAL will call linkToDeath with the callee's
+     * binder token. The recommended implementation is to close this session if the callee dies,
+     * to prevent subsequent createSession calls from failing.
+     *
      * @param sensorId The sensorId for which this session is being created.
      * @param userId The userId for which this session is being created.
      * @param cb A callback to notify the framework about the session's events.
diff --git a/biometrics/fingerprint/2.1/vts/functional/Android.bp b/biometrics/fingerprint/2.1/vts/functional/Android.bp
index 0935bf6..68b3360 100644
--- a/biometrics/fingerprint/2.1/vts/functional/Android.bp
+++ b/biometrics/fingerprint/2.1/vts/functional/Android.bp
@@ -26,6 +26,7 @@
 cc_test {
     name: "VtsHalBiometricsFingerprintV2_1TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: ["VtsHalBiometricsFingerprintV2_1TargetTest.cpp"],
     srcs: ["VtsHalBiometricsFingerprintV2_1TargetTest.cpp"],
     static_libs: ["android.hardware.biometrics.fingerprint@2.1"],
     test_suites: ["general-tests", "vts"],
diff --git a/bluetooth/1.0/Android.bp b/bluetooth/1.0/Android.bp
index 8d023c0..20775dd 100644
--- a/bluetooth/1.0/Android.bp
+++ b/bluetooth/1.0/Android.bp
@@ -21,4 +21,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.bluetooth",
+    ],
 }
diff --git a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml
index 09463c9..ea7adc9 100644
--- a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml
+++ b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml
@@ -22,8 +22,11 @@
     <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup">
     </target_preparer>
 
-    <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
-        <option name="bluetooth" value="off" />
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="settings put global ble_scan_always_enabled 0" />
+        <option name="run-command" value="su u$(am get-current-user)_system svc bluetooth disable" />
+        <option name="teardown-command" value="su u$(am get-current-user)_system svc bluetooth enable" />
+        <option name="teardown-command" value="settings put global ble_scan_always_enabled 1" />
     </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
diff --git a/bluetooth/1.1/Android.bp b/bluetooth/1.1/Android.bp
index 4feb28b..4ac2009 100644
--- a/bluetooth/1.1/Android.bp
+++ b/bluetooth/1.1/Android.bp
@@ -21,4 +21,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.bluetooth",
+    ],
 }
diff --git a/bluetooth/a2dp/1.0/Android.bp b/bluetooth/a2dp/1.0/Android.bp
index 7f39d4f..20776dc 100644
--- a/bluetooth/a2dp/1.0/Android.bp
+++ b/bluetooth/a2dp/1.0/Android.bp
@@ -21,4 +21,8 @@
         "android.hidl.base@1.0",
     ],
     gen_java: false,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.bluetooth",
+    ],
 }
diff --git a/bluetooth/audio/2.0/Android.bp b/bluetooth/audio/2.0/Android.bp
index dd39f9f..e4d48c1 100644
--- a/bluetooth/audio/2.0/Android.bp
+++ b/bluetooth/audio/2.0/Android.bp
@@ -24,4 +24,8 @@
         "android.hidl.safe_union@1.0",
     ],
     gen_java: false,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.bluetooth",
+    ],
 }
diff --git a/bluetooth/audio/2.1/vts/functional/Android.bp b/bluetooth/audio/2.1/vts/functional/Android.bp
index 3314a8a..cea7326 100644
--- a/bluetooth/audio/2.1/vts/functional/Android.bp
+++ b/bluetooth/audio/2.1/vts/functional/Android.bp
@@ -10,6 +10,7 @@
 cc_test {
     name: "VtsHalBluetoothAudioV2_1TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: ["VtsHalBluetoothAudioV2_1TargetTest.cpp"],
     srcs: ["VtsHalBluetoothAudioV2_1TargetTest.cpp"],
     static_libs: [
         "android.hardware.audio.common@5.0",
diff --git a/bluetooth/audio/2.2/Android.bp b/bluetooth/audio/2.2/Android.bp
deleted file mode 100644
index d66e84e..0000000
--- a/bluetooth/audio/2.2/Android.bp
+++ /dev/null
@@ -1,33 +0,0 @@
-// This file is autogenerated by hidl-gen -Landroidbp.
-
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "hardware_interfaces_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-hidl_interface {
-    name: "android.hardware.bluetooth.audio@2.2",
-    root: "android.hardware",
-    srcs: [
-        "types.hal",
-        "IBluetoothAudioPort.hal",
-        "IBluetoothAudioProvider.hal",
-        "IBluetoothAudioProvidersFactory.hal",
-    ],
-    interfaces: [
-        "android.hardware.audio.common@5.0",
-        "android.hardware.bluetooth.audio@2.0",
-        "android.hardware.bluetooth.audio@2.1",
-        "android.hidl.base@1.0",
-        "android.hidl.safe_union@1.0",
-    ],
-    apex_available: [
-        "//apex_available:platform",
-        "com.android.bluetooth",
-    ],
-    gen_java: false,
-}
diff --git a/bluetooth/audio/2.2/IBluetoothAudioPort.hal b/bluetooth/audio/2.2/IBluetoothAudioPort.hal
deleted file mode 100644
index 344899c..0000000
--- a/bluetooth/audio/2.2/IBluetoothAudioPort.hal
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.bluetooth.audio@2.2;
-
-import @2.0::IBluetoothAudioPort;
-import android.hardware.audio.common@5.0::SinkMetadata;
-
-interface IBluetoothAudioPort extends @2.0::IBluetoothAudioPort  {
-    /**
-     * Called when the metadata of the stream's sink has been changed.
-     *
-     * @param sinkMetadata Description of the audio that is recorded by the
-     *    clients.
-     */
-    updateSinkMetadata(SinkMetadata sinkMetadata);
-};
diff --git a/bluetooth/audio/2.2/IBluetoothAudioProvider.hal b/bluetooth/audio/2.2/IBluetoothAudioProvider.hal
deleted file mode 100644
index 7c91805..0000000
--- a/bluetooth/audio/2.2/IBluetoothAudioProvider.hal
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.bluetooth.audio@2.2;
-
-import @2.1::IBluetoothAudioProvider;
-import @2.2::IBluetoothAudioPort;
-import @2.0::Status;
-
-/**
- * HAL interface from the Bluetooth stack to the Audio HAL
- *
- * The Bluetooth stack calls methods in this interface to start and end audio
- * sessions and sends callback events to the Audio HAL.
- *
- * Note: For HIDL APIs with a "generates" statement, the callback parameter used
- * for return value must be invoked synchronously before the API call returns.
- */
-interface IBluetoothAudioProvider extends @2.1::IBluetoothAudioProvider {
-
-    /**
-     * This method indicates that the Bluetooth stack is ready to stream audio.
-     * It registers an instance of IBluetoothAudioPort with and provides the
-     * current negotiated codec to the Audio HAL. After this method is called,
-     * the Audio HAL can invoke IBluetoothAudioPort.startStream().
-     *
-     * Note: endSession() must be called to unregister this IBluetoothAudioPort
-     *
-     * @param hostIf An instance of IBluetoothAudioPort for stream control
-     * @param audioConfig The audio configuration negotiated with the remote
-     *    device. The PCM parameters are set if software based encoding,
-     *    otherwise the correct codec configuration is used for hardware
-     *    encoding.
-     *
-     * @return status One of the following
-     *    SUCCESS if this IBluetoothAudioPort was successfully registered with
-     *        the Audio HAL
-     *    UNSUPPORTED_CODEC_CONFIGURATION if the Audio HAL cannot register this
-     *        IBluetoothAudioPort with the given codec configuration
-     *    FAILURE if the Audio HAL cannot register this IBluetoothAudioPort for
-     *        any other reason
-     * @return dataMQ The fast message queue for audio data from/to this
-     *    provider. Audio data will be in PCM format as specified by the
-     *    audioConfig.pcmConfig parameter. Invalid if streaming is offloaded
-     *    from/to hardware or on failure.
-     */
-    startSession_2_2(IBluetoothAudioPort hostIf, AudioConfiguration audioConfig)
-                generates (Status status, fmq_sync<uint8_t> dataMQ);
-
-    /**
-     * Called when the audio configuration of the stream has been changed.
-     *
-     * @param audioConfig The audio configuration negotiated with the remote
-     *    device. The PCM parameters are set if software based encoding,
-     *    otherwise the correct codec configuration is used for hardware
-     *    encoding.
-     */
-    updateAudioConfiguration(AudioConfiguration audioConfig);
-
-    /**
-     * Called when the supported latency mode is updated.
-     *
-     * @param allowed If the peripheral devices can't keep up with low latency
-     * mode, the API will be called with supported is false.
-     */
-    setLowLatencyModeAllowed(bool allowed);
-};
diff --git a/bluetooth/audio/2.2/IBluetoothAudioProvidersFactory.hal b/bluetooth/audio/2.2/IBluetoothAudioProvidersFactory.hal
deleted file mode 100644
index ae9c598..0000000
--- a/bluetooth/audio/2.2/IBluetoothAudioProvidersFactory.hal
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.bluetooth.audio@2.2;
-
-import IBluetoothAudioProvider;
-import @2.1::IBluetoothAudioProvidersFactory;
-import @2.0::Status;
-import @2.1::SessionType;
-
-/**
- * This factory allows a HAL implementation to be split into multiple
- * independent providers.
- *
- * When the Bluetooth stack is ready to create an audio session, it must first
- * obtain the IBluetoothAudioProvider for that session type by calling
- * openProvider().
- *
- * Note: For HIDL APIs with a "generates" statement, the callback parameter used
- * for return value must be invoked synchronously before the API call returns.
- */
-interface IBluetoothAudioProvidersFactory extends @2.1::IBluetoothAudioProvidersFactory {
-    /**
-     * Opens an audio provider for a session type. To close the provider, it is
-     * necessary to release references to the returned provider object.
-     *
-     * @param sessionType The session type (e.g.
-     *    LE_AUDIO_SOFTWARE_ENCODING_DATAPATH).
-     *
-     * @return status One of the following
-     *    SUCCESS if the Audio HAL successfully opens the provider with the
-     *        given session type
-     *    FAILURE if the Audio HAL cannot open the provider
-     * @return provider The provider of the specified session type
-     */
-    openProvider_2_2(SessionType sessionType)
-        generates (Status status, IBluetoothAudioProvider provider);
-
-    /**
-     * Gets a list of audio capabilities for a session type.
-     *
-     * For software encoding, the PCM capabilities are returned.
-     * For hardware encoding, the supported codecs and their capabilities are
-     * returned.
-     *
-     * @param sessionType The session type (e.g.
-     *    A2DP_SOFTWARE_ENCODING_DATAPATH).
-     * @return audioCapabilities A list containing all the capabilities
-     *    supported by the sesson type. The capabilities is a list of
-     *    available options when configuring the codec for the session.
-     *    For software encoding it is the PCM data rate.
-     *    For hardware encoding it is the list of supported codecs and their
-     *    capabilities.
-     *    If a provider isn't supported, an empty list should be returned.
-     *    Note: Only one entry should exist per codec when using hardware
-     *    encoding.
-     */
-     getProviderCapabilities_2_2(SessionType sessionType)
-         generates (vec<AudioCapabilities> audioCapabilities);
-};
diff --git a/bluetooth/audio/2.2/OWNERS b/bluetooth/audio/2.2/OWNERS
deleted file mode 100644
index 84f5b1e..0000000
--- a/bluetooth/audio/2.2/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-aliceypkuo@google.com
-ugoyu@google.com
-sattiraju@google.com
diff --git a/bluetooth/audio/2.2/default/A2dpOffloadAudioProvider.cpp b/bluetooth/audio/2.2/default/A2dpOffloadAudioProvider.cpp
deleted file mode 100644
index 2a6d93a..0000000
--- a/bluetooth/audio/2.2/default/A2dpOffloadAudioProvider.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BTAudioProviderA2dpOffload"
-
-#include "A2dpOffloadAudioProvider.h"
-
-#include <android-base/logging.h>
-#include <fmq/MessageQueue.h>
-#include <hidl/MQDescriptor.h>
-
-#include "BluetoothAudioSessionReport_2_2.h"
-#include "BluetoothAudioSupportedCodecsDB_2_1.h"
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace audio {
-namespace V2_2 {
-namespace implementation {
-
-using ::android::bluetooth::audio::BluetoothAudioSessionReport_2_2;
-using ::android::hardware::kSynchronizedReadWrite;
-using ::android::hardware::MessageQueue;
-using ::android::hardware::Void;
-using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
-
-using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
-
-A2dpOffloadAudioProvider::A2dpOffloadAudioProvider()
-    : BluetoothAudioProvider() {
-  session_type_ = V2_1::SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH;
-}
-
-bool A2dpOffloadAudioProvider::isValid(const V2_0::SessionType& sessionType) {
-  return isValid(static_cast<V2_1::SessionType>(sessionType));
-}
-
-bool A2dpOffloadAudioProvider::isValid(const V2_1::SessionType& sessionType) {
-  return (sessionType == session_type_);
-}
-
-Return<void> A2dpOffloadAudioProvider::startSession(
-    const sp<V2_0::IBluetoothAudioPort>& hostIf,
-    const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
-  /**
-   * Initialize the audio platform if audioConfiguration is supported.
-   * Save the IBluetoothAudioPort interface, so that it can be used
-   * later to send stream control commands to the HAL client, based on
-   * interaction with Audio framework.
-   */
-  if (audioConfig.getDiscriminator() !=
-      AudioConfiguration::hidl_discriminator::codecConfig) {
-    LOG(WARNING) << __func__
-                 << " - Invalid Audio Configuration=" << toString(audioConfig);
-    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
-             DataMQ::Descriptor());
-    return Void();
-  } else if (!android::bluetooth::audio::IsOffloadCodecConfigurationValid(
-                 session_type_, audioConfig.codecConfig())) {
-    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
-             DataMQ::Descriptor());
-    return Void();
-  }
-
-  return BluetoothAudioProvider::startSession(hostIf, audioConfig, _hidl_cb);
-}
-
-Return<void> A2dpOffloadAudioProvider::onSessionReady(
-    startSession_cb _hidl_cb) {
-  BluetoothAudioSessionReport_2_2::OnSessionStarted(session_type_, stack_iface_,
-                                                    nullptr, audio_config_);
-  _hidl_cb(BluetoothAudioStatus::SUCCESS, DataMQ::Descriptor());
-  return Void();
-}
-
-}  // namespace implementation
-}  // namespace V2_2
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
diff --git a/bluetooth/audio/2.2/default/A2dpOffloadAudioProvider.h b/bluetooth/audio/2.2/default/A2dpOffloadAudioProvider.h
deleted file mode 100644
index 7ccdedc..0000000
--- a/bluetooth/audio/2.2/default/A2dpOffloadAudioProvider.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "BluetoothAudioProvider.h"
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace audio {
-namespace V2_2 {
-namespace implementation {
-
-class A2dpOffloadAudioProvider : public BluetoothAudioProvider {
- public:
-  A2dpOffloadAudioProvider();
-
-  bool isValid(const V2_1::SessionType& sessionType) override;
-  bool isValid(const V2_0::SessionType& sessionType) override;
-
-  Return<void> startSession(const sp<V2_0::IBluetoothAudioPort>& hostIf,
-                            const V2_0::AudioConfiguration& audioConfig,
-                            startSession_cb _hidl_cb) override;
-
- private:
-  Return<void> onSessionReady(startSession_cb _hidl_cb) override;
-};
-
-}  // namespace implementation
-}  // namespace V2_2
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
diff --git a/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.cpp b/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.cpp
deleted file mode 100644
index eb87178..0000000
--- a/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BTAudioProviderA2dpSoftware"
-
-#include "A2dpSoftwareAudioProvider.h"
-
-#include <android-base/logging.h>
-
-#include "BluetoothAudioSessionReport_2_2.h"
-#include "BluetoothAudioSupportedCodecsDB_2_2.h"
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace audio {
-namespace V2_2 {
-namespace implementation {
-
-using ::android::bluetooth::audio::BluetoothAudioSessionReport_2_2;
-using ::android::hardware::Void;
-using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
-
-// Here the buffer size is based on SBC
-static constexpr uint32_t kPcmFrameSize = 4;  // 16 bits per sample / stereo
-// SBC is 128, and here we choose the LCM of 16, 24, and 32
-static constexpr uint32_t kPcmFrameCount = 96;
-static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount;
-// The max counts by 1 tick (20ms) for SBC is about 7. Since using 96 for the
-// PCM counts, here we just choose a greater number
-static constexpr uint32_t kRtpFrameCount = 10;
-static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount;
-static constexpr uint32_t kBufferCount = 2;  // double buffer
-static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount;
-
-A2dpSoftwareAudioProvider::A2dpSoftwareAudioProvider()
-    : BluetoothAudioProvider(), mDataMQ(nullptr) {
-  LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
-            << " byte(s)";
-  std::unique_ptr<DataMQ> tempDataMQ(
-      new DataMQ(kDataMqSize, /* EventFlag */ true));
-  if (tempDataMQ && tempDataMQ->isValid()) {
-    mDataMQ = std::move(tempDataMQ);
-    session_type_ = V2_1::SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH;
-  } else {
-    ALOGE_IF(!tempDataMQ, "failed to allocate data MQ");
-    ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "data MQ is invalid");
-  }
-}
-
-bool A2dpSoftwareAudioProvider::isValid(const V2_0::SessionType& sessionType) {
-  return isValid(static_cast<V2_1::SessionType>(sessionType));
-}
-
-bool A2dpSoftwareAudioProvider::isValid(const V2_1::SessionType& sessionType) {
-  return (sessionType == session_type_ && mDataMQ && mDataMQ->isValid());
-}
-
-Return<void> A2dpSoftwareAudioProvider::startSession(
-    const sp<V2_0::IBluetoothAudioPort>& hostIf,
-    const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
-  /**
-   * Initialize the audio platform if audioConfiguration is supported.
-   * Save the IBluetoothAudioPort interface, so that it can be used
-   * later to send stream control commands to the HAL client, based on
-   * interaction with Audio framework.
-   */
-  if (audioConfig.getDiscriminator() !=
-      AudioConfiguration::hidl_discriminator::pcmConfig) {
-    LOG(WARNING) << __func__
-                 << " - Invalid Audio Configuration=" << toString(audioConfig);
-    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
-             DataMQ::Descriptor());
-    return Void();
-  } else if (!android::bluetooth::audio::IsSoftwarePcmConfigurationValid(
-                 audioConfig.pcmConfig())) {
-    LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
-                 << toString(audioConfig.pcmConfig());
-    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
-             DataMQ::Descriptor());
-    return Void();
-  }
-
-  return BluetoothAudioProvider::startSession(hostIf, audioConfig, _hidl_cb);
-}
-
-Return<void> A2dpSoftwareAudioProvider::onSessionReady(
-    startSession_cb _hidl_cb) {
-  if (mDataMQ && mDataMQ->isValid()) {
-    BluetoothAudioSessionReport_2_2::OnSessionStarted(
-        session_type_, stack_iface_, mDataMQ->getDesc(), audio_config_);
-    _hidl_cb(BluetoothAudioStatus::SUCCESS, *mDataMQ->getDesc());
-  } else {
-    _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
-  }
-  return Void();
-}
-
-}  // namespace implementation
-}  // namespace V2_2
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
diff --git a/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.h b/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.h
deleted file mode 100644
index ac3aece..0000000
--- a/bluetooth/audio/2.2/default/A2dpSoftwareAudioProvider.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <fmq/MessageQueue.h>
-#include <hidl/MQDescriptor.h>
-
-#include "BluetoothAudioProvider.h"
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace audio {
-namespace V2_2 {
-namespace implementation {
-
-using ::android::hardware::kSynchronizedReadWrite;
-using ::android::hardware::MessageQueue;
-
-using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
-
-class A2dpSoftwareAudioProvider : public BluetoothAudioProvider {
- public:
-  A2dpSoftwareAudioProvider();
-
-  bool isValid(const V2_1::SessionType& sessionType) override;
-  bool isValid(const V2_0::SessionType& sessionType) override;
-
-  Return<void> startSession(const sp<V2_0::IBluetoothAudioPort>& hostIf,
-                            const V2_0::AudioConfiguration& audioConfig,
-                            startSession_cb _hidl_cb) override;
-
- private:
-  // audio data queue for software encoding
-  std::unique_ptr<DataMQ> mDataMQ;
-
-  Return<void> onSessionReady(startSession_cb _hidl_cb) override;
-};
-
-}  // namespace implementation
-}  // namespace V2_2
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
diff --git a/bluetooth/audio/2.2/default/Android.bp b/bluetooth/audio/2.2/default/Android.bp
deleted file mode 100644
index 7a5ae75..0000000
--- a/bluetooth/audio/2.2/default/Android.bp
+++ /dev/null
@@ -1,37 +0,0 @@
-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: "android.hardware.bluetooth.audio@2.2-impl",
-    defaults: ["hidl_defaults"],
-    vendor: true,
-    relative_install_path: "hw",
-    srcs: [
-        "BluetoothAudioProvidersFactory.cpp",
-        "BluetoothAudioProvider.cpp",
-        "A2dpOffloadAudioProvider.cpp",
-        "A2dpSoftwareAudioProvider.cpp",
-        "HearingAidAudioProvider.cpp",
-        "LeAudioAudioProvider.cpp",
-        "LeAudioOffloadAudioProvider.cpp",
-    ],
-    header_libs: ["libhardware_headers"],
-    shared_libs: [
-        "android.hardware.bluetooth.audio@2.0",
-        "android.hardware.bluetooth.audio@2.1",
-        "android.hardware.bluetooth.audio@2.2",
-        "libbase",
-        "libbluetooth_audio_session",
-        "libcutils",
-        "libfmq",
-        "libhidlbase",
-        "liblog",
-        "libutils",
-    ],
-}
diff --git a/bluetooth/audio/2.2/default/AudioPort_2_0_to_2_2_Wrapper.h b/bluetooth/audio/2.2/default/AudioPort_2_0_to_2_2_Wrapper.h
deleted file mode 100644
index c5613fb..0000000
--- a/bluetooth/audio/2.2/default/AudioPort_2_0_to_2_2_Wrapper.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android/hardware/bluetooth/audio/2.2/types.h>
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace audio {
-namespace V2_2 {
-namespace implementation {
-
-using ::android::sp;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::audio::common::V5_0::SinkMetadata;
-using ::android::hardware::audio::common::V5_0::SourceMetadata;
-using ::android::hardware::bluetooth::audio::V2_2::IBluetoothAudioPort;
-
-class AudioPort_2_0_to_2_2_Wrapper : public V2_2::IBluetoothAudioPort {
- public:
-  AudioPort_2_0_to_2_2_Wrapper(const sp<V2_0::IBluetoothAudioPort>& port) {
-    this->port = port;
-  }
-
-  Return<void> startStream() override { return port->startStream(); }
-  Return<void> suspendStream() override { return port->suspendStream(); }
-  Return<void> stopStream() override { return port->stopStream(); }
-  Return<void> getPresentationPosition(
-      getPresentationPosition_cb _hidl_cb) override {
-    return port->getPresentationPosition(_hidl_cb);
-  }
-  Return<void> updateMetadata(const SourceMetadata& sourceMetadata) override {
-    return port->updateMetadata(sourceMetadata);
-  }
-  Return<void> updateSinkMetadata(const SinkMetadata&) override {
-    // DO NOTHING, 2.0 AudioPort doesn't support sink metadata updates
-    return Void();
-  }
-
-  sp<V2_0::IBluetoothAudioPort> port;
-};
-
-}  // namespace implementation
-}  // namespace V2_2
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
\ No newline at end of file
diff --git a/bluetooth/audio/2.2/default/BluetoothAudioProvider.cpp b/bluetooth/audio/2.2/default/BluetoothAudioProvider.cpp
deleted file mode 100644
index 62511e9..0000000
--- a/bluetooth/audio/2.2/default/BluetoothAudioProvider.cpp
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BTAudioProviderStub"
-
-#include "BluetoothAudioProvider.h"
-
-#include <android-base/logging.h>
-
-#include "AudioPort_2_0_to_2_2_Wrapper.h"
-#include "BluetoothAudioSessionReport_2_2.h"
-#include "BluetoothAudioSupportedCodecsDB_2_2.h"
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace audio {
-namespace V2_2 {
-namespace implementation {
-
-using ::android::bluetooth::audio::BluetoothAudioSessionReport_2_2;
-using ::android::hardware::kSynchronizedReadWrite;
-using ::android::hardware::MessageQueue;
-using ::android::hardware::Void;
-
-using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
-
-void BluetoothAudioDeathRecipient::serviceDied(
-    uint64_t cookie __unused,
-    const wp<::android::hidl::base::V1_0::IBase>& who __unused) {
-  LOG(ERROR) << "BluetoothAudioDeathRecipient::" << __func__
-             << " - BluetoothAudio Service died";
-  provider_->endSession();
-}
-
-BluetoothAudioProvider::BluetoothAudioProvider()
-    : death_recipient_(new BluetoothAudioDeathRecipient(this)),
-      session_type_(V2_1::SessionType::UNKNOWN),
-      audio_config_({}) {}
-
-Return<void> BluetoothAudioProvider::startSession(
-    const sp<V2_0::IBluetoothAudioPort>& hostIf,
-    const V2_0::AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
-  AudioConfiguration audioConfig_2_2;
-
-  if (audioConfig.getDiscriminator() ==
-      V2_0::AudioConfiguration::hidl_discriminator::pcmConfig) {
-    audioConfig_2_2.pcmConfig(
-        {.sampleRate =
-             static_cast<V2_1::SampleRate>(audioConfig.pcmConfig().sampleRate),
-         .channelMode = audioConfig.pcmConfig().channelMode,
-         .bitsPerSample = audioConfig.pcmConfig().bitsPerSample,
-         .dataIntervalUs = 0});
-  } else {
-    audioConfig_2_2.codecConfig(audioConfig.codecConfig());
-  }
-
-  sp<V2_2::IBluetoothAudioPort> hostIf_2_2 =
-      new AudioPort_2_0_to_2_2_Wrapper(hostIf);
-  return startSession_2_2(hostIf_2_2, audioConfig_2_2, _hidl_cb);
-}
-
-Return<void> BluetoothAudioProvider::startSession_2_1(
-    const sp<V2_0::IBluetoothAudioPort>& hostIf,
-    const V2_1::AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
-  AudioConfiguration audioConfig_2_2;
-  if (audioConfig.getDiscriminator() ==
-      V2_1::AudioConfiguration::hidl_discriminator::leAudioCodecConfig) {
-    audioConfig_2_2.leAudioConfig().mode = LeAudioMode::UNKNOWN;
-    audioConfig_2_2.leAudioConfig().config.unicastConfig() = {
-        .streamMap = {{
-            .streamHandle = 0xFFFF,
-            .audioChannelAllocation =
-                audioConfig.leAudioCodecConfig().audioChannelAllocation,
-        }},
-        .peerDelay = 0,
-        .lc3Config = audioConfig.leAudioCodecConfig().lc3Config};
-  } else if (audioConfig.getDiscriminator() ==
-             V2_1::AudioConfiguration::hidl_discriminator::pcmConfig) {
-    audioConfig_2_2.pcmConfig(audioConfig.pcmConfig());
-  } else {
-    audioConfig_2_2.codecConfig(audioConfig.codecConfig());
-  }
-
-  sp<V2_2::IBluetoothAudioPort> hostIf_2_2 =
-      new AudioPort_2_0_to_2_2_Wrapper(hostIf);
-  return startSession_2_2(hostIf_2_2, audioConfig_2_2, _hidl_cb);
-}
-
-Return<void> BluetoothAudioProvider::startSession_2_2(
-    const sp<V2_2::IBluetoothAudioPort>& hostIf,
-    const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
-  if (hostIf == nullptr) {
-    _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
-    return Void();
-  }
-
-  /**
-   * Initialize the audio platform if audioConfiguration is supported.
-   * Save the IBluetoothAudioPort interface, so that it can be used
-   * later to send stream control commands to the HAL client, based on
-   * interaction with Audio framework.
-   */
-  audio_config_ = audioConfig;
-  stack_iface_ = hostIf;
-  stack_iface_->linkToDeath(death_recipient_, 0);
-
-  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
-            << ", AudioConfiguration=[" << toString(audio_config_) << "]";
-
-  onSessionReady(_hidl_cb);
-  return Void();
-}
-
-Return<void> BluetoothAudioProvider::streamStarted(
-    BluetoothAudioStatus status) {
-  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
-            << ", status=" << toString(status);
-
-  /**
-   * Streaming on control path has started,
-   * HAL server should start the streaming on data path.
-   */
-  if (stack_iface_) {
-    BluetoothAudioSessionReport_2_2::ReportControlStatus(session_type_, true,
-                                                         status);
-  } else {
-    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
-                 << ", status=" << toString(status) << " has NO session";
-  }
-
-  return Void();
-}
-
-Return<void> BluetoothAudioProvider::streamSuspended(
-    BluetoothAudioStatus status) {
-  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
-            << ", status=" << toString(status);
-
-  /**
-   * Streaming on control path has suspend,
-   * HAL server should suspend the streaming on data path.
-   */
-  if (stack_iface_) {
-    BluetoothAudioSessionReport_2_2::ReportControlStatus(session_type_, false,
-                                                         status);
-  } else {
-    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
-                 << ", status=" << toString(status) << " has NO session";
-  }
-
-  return Void();
-}
-
-Return<void> BluetoothAudioProvider::endSession() {
-  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
-
-  if (stack_iface_) {
-    BluetoothAudioSessionReport_2_2::OnSessionEnded(session_type_);
-    stack_iface_->unlinkToDeath(death_recipient_);
-  } else {
-    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
-              << " has NO session";
-  }
-
-  /**
-   * Clean up the audio platform as remote audio device is no
-   * longer active
-   */
-  stack_iface_ = nullptr;
-  audio_config_ = {};
-
-  return Void();
-}
-
-Return<void> BluetoothAudioProvider::updateAudioConfiguration(
-    const AudioConfiguration& audioConfig) {
-  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
-
-  if (stack_iface_ == nullptr) {
-    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
-              << " has NO session";
-    return Void();
-  }
-
-  if (audioConfig.getDiscriminator() != audio_config_.getDiscriminator()) {
-    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
-              << " audio config type is not match";
-    return Void();
-  }
-
-  audio_config_ = audioConfig;
-  BluetoothAudioSessionReport_2_2::ReportAudioConfigChanged(session_type_,
-                                                            audio_config_);
-
-  return Void();
-}
-
-Return<void> BluetoothAudioProvider::setLowLatencyModeAllowed(bool allowed) {
-  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
-
-  if (stack_iface_ == nullptr) {
-    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
-              << " has NO session";
-    return Void();
-  }
-  LOG(INFO) << __func__ << " allowed: " << allowed;
-  return Void();
-}
-
-}  // namespace implementation
-}  // namespace V2_2
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
diff --git a/bluetooth/audio/2.2/default/BluetoothAudioProvider.h b/bluetooth/audio/2.2/default/BluetoothAudioProvider.h
deleted file mode 100644
index 90c158e..0000000
--- a/bluetooth/audio/2.2/default/BluetoothAudioProvider.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android/hardware/bluetooth/audio/2.2/IBluetoothAudioProvider.h>
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace audio {
-namespace V2_2 {
-namespace implementation {
-
-using ::android::sp;
-using ::android::hardware::bluetooth::audio::V2_2::IBluetoothAudioPort;
-
-using BluetoothAudioStatus =
-    ::android::hardware::bluetooth::audio::V2_0::Status;
-
-class BluetoothAudioDeathRecipient;
-
-class BluetoothAudioProvider : public IBluetoothAudioProvider {
- public:
-  BluetoothAudioProvider();
-  ~BluetoothAudioProvider() = default;
-
-  virtual bool isValid(const V2_1::SessionType& sessionType) = 0;
-  virtual bool isValid(const V2_0::SessionType& sessionType) = 0;
-
-  Return<void> startSession(const sp<V2_0::IBluetoothAudioPort>& hostIf,
-                            const V2_0::AudioConfiguration& audioConfig,
-                            startSession_cb _hidl_cb) override;
-  Return<void> startSession_2_1(const sp<V2_0::IBluetoothAudioPort>& hostIf,
-                                const V2_1::AudioConfiguration& audioConfig,
-                                startSession_cb _hidl_cb) override;
-  Return<void> startSession_2_2(const sp<V2_2::IBluetoothAudioPort>& hostIf,
-                                const AudioConfiguration& audioConfig,
-                                startSession_cb _hidl_cb) override;
-  Return<void> streamStarted(BluetoothAudioStatus status) override;
-  Return<void> streamSuspended(BluetoothAudioStatus status) override;
-  Return<void> endSession() override;
-  Return<void> updateAudioConfiguration(
-      const AudioConfiguration& audioConfig) override;
-
-  Return<void> setLowLatencyModeAllowed(bool allowed) override;
-
- protected:
-  sp<BluetoothAudioDeathRecipient> death_recipient_;
-
-  V2_1::SessionType session_type_;
-  AudioConfiguration audio_config_;
-  sp<V2_2::IBluetoothAudioPort> stack_iface_;
-
-  virtual Return<void> onSessionReady(startSession_cb _hidl_cb) = 0;
-};
-
-class BluetoothAudioDeathRecipient : public hidl_death_recipient {
- public:
-  BluetoothAudioDeathRecipient(const sp<BluetoothAudioProvider> provider)
-      : provider_(provider) {}
-
-  virtual void serviceDied(
-      uint64_t cookie,
-      const wp<::android::hidl::base::V1_0::IBase>& who) override;
-
- private:
-  sp<BluetoothAudioProvider> provider_;
-};
-
-}  // namespace implementation
-}  // namespace V2_2
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
diff --git a/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.cpp b/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.cpp
deleted file mode 100644
index 490a436..0000000
--- a/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.cpp
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BTAudioProvidersFactory"
-
-#include "BluetoothAudioProvidersFactory.h"
-
-#include <android-base/logging.h>
-
-#include "BluetoothAudioSupportedCodecsDB_2_2.h"
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace audio {
-namespace V2_2 {
-namespace implementation {
-
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Void;
-using ::android::hardware::bluetooth::audio::V2_0::CodecCapabilities;
-
-A2dpSoftwareAudioProvider
-    BluetoothAudioProvidersFactory::a2dp_software_provider_instance_;
-A2dpOffloadAudioProvider
-    BluetoothAudioProvidersFactory::a2dp_offload_provider_instance_;
-HearingAidAudioProvider
-    BluetoothAudioProvidersFactory::hearing_aid_provider_instance_;
-LeAudioOutputAudioProvider
-    BluetoothAudioProvidersFactory::leaudio_output_provider_instance_;
-LeAudioOffloadOutputAudioProvider
-    BluetoothAudioProvidersFactory::leaudio_offload_output_provider_instance_;
-LeAudioInputAudioProvider
-    BluetoothAudioProvidersFactory::leaudio_input_provider_instance_;
-LeAudioOffloadInputAudioProvider
-    BluetoothAudioProvidersFactory::leaudio_offload_input_provider_instance_;
-
-Return<void> BluetoothAudioProvidersFactory::openProvider(
-    const V2_0::SessionType sessionType, openProvider_cb _hidl_cb) {
-  LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType);
-  BluetoothAudioStatus status = BluetoothAudioStatus::SUCCESS;
-  BluetoothAudioProvider* provider = nullptr;
-
-  switch (sessionType) {
-    case V2_0::SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH:
-      provider = &a2dp_software_provider_instance_;
-      break;
-    case V2_0::SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH:
-      provider = &a2dp_offload_provider_instance_;
-      break;
-    case V2_0::SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH:
-      provider = &hearing_aid_provider_instance_;
-      break;
-    default:
-      status = BluetoothAudioStatus::FAILURE;
-  }
-
-  if (provider == nullptr || !provider->isValid(sessionType)) {
-    provider = nullptr;
-    status = BluetoothAudioStatus::FAILURE;
-    LOG(ERROR) << __func__ << " - SessionType=" << toString(sessionType)
-               << ", status=" << toString(status);
-  }
-
-  _hidl_cb(status, provider);
-  return Void();
-}
-
-Return<void> BluetoothAudioProvidersFactory::openProvider_2_1(
-    const V2_1::SessionType sessionType, openProvider_2_1_cb _hidl_cb) {
-  LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType);
-  BluetoothAudioStatus status = BluetoothAudioStatus::SUCCESS;
-  BluetoothAudioProvider* provider = nullptr;
-
-  switch (sessionType) {
-    case V2_1::SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH:
-      provider = &a2dp_software_provider_instance_;
-      break;
-    case V2_1::SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH:
-      provider = &a2dp_offload_provider_instance_;
-      break;
-    case V2_1::SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH:
-      provider = &hearing_aid_provider_instance_;
-      break;
-    case V2_1::SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH:
-      provider = &leaudio_output_provider_instance_;
-      break;
-    case V2_1::SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH:
-      provider = &leaudio_input_provider_instance_;
-      break;
-    default:
-      status = BluetoothAudioStatus::FAILURE;
-  }
-
-  if (provider == nullptr || !provider->isValid(sessionType)) {
-    provider = nullptr;
-    status = BluetoothAudioStatus::FAILURE;
-    LOG(ERROR) << __func__ << " - SessionType=" << toString(sessionType)
-               << ", status=" << toString(status);
-  }
-
-  _hidl_cb(status, provider);
-  return Void();
-}
-
-Return<void> BluetoothAudioProvidersFactory::openProvider_2_2(
-    const V2_1::SessionType sessionType, openProvider_2_2_cb _hidl_cb) {
-  LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType);
-  BluetoothAudioStatus status = BluetoothAudioStatus::SUCCESS;
-  BluetoothAudioProvider* provider = nullptr;
-
-  switch (sessionType) {
-    case V2_1::SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH:
-      provider = &a2dp_software_provider_instance_;
-      break;
-    case V2_1::SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH:
-      provider = &a2dp_offload_provider_instance_;
-      break;
-    case V2_1::SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH:
-      provider = &hearing_aid_provider_instance_;
-      break;
-    case V2_1::SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH:
-      provider = &leaudio_output_provider_instance_;
-      break;
-    case V2_1::SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
-      provider = &leaudio_offload_output_provider_instance_;
-      break;
-    case V2_1::SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH:
-      provider = &leaudio_input_provider_instance_;
-      break;
-    case V2_1::SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
-      provider = &leaudio_offload_input_provider_instance_;
-      break;
-    default:
-      status = BluetoothAudioStatus::FAILURE;
-  }
-
-  if (provider == nullptr || !provider->isValid(sessionType)) {
-    provider = nullptr;
-    status = BluetoothAudioStatus::FAILURE;
-    LOG(ERROR) << __func__ << " - SessionType=" << toString(sessionType)
-               << ", status=" << toString(status);
-  }
-
-  _hidl_cb(status, provider);
-  return Void();
-}
-
-Return<void> BluetoothAudioProvidersFactory::getProviderCapabilities(
-    const V2_0::SessionType sessionType, getProviderCapabilities_cb _hidl_cb) {
-  hidl_vec<V2_0::AudioCapabilities> audio_capabilities =
-      hidl_vec<V2_0::AudioCapabilities>(0);
-  if (sessionType == V2_0::SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
-    std::vector<CodecCapabilities> db_codec_capabilities =
-        android::bluetooth::audio::GetOffloadCodecCapabilities(sessionType);
-    if (db_codec_capabilities.size()) {
-      audio_capabilities.resize(db_codec_capabilities.size());
-      for (int i = 0; i < db_codec_capabilities.size(); ++i) {
-        audio_capabilities[i].codecCapabilities(db_codec_capabilities[i]);
-      }
-    }
-  } else if (sessionType != V2_0::SessionType::UNKNOWN) {
-    std::vector<::android::hardware::bluetooth::audio::V2_0::PcmParameters>
-        db_pcm_capabilities =
-            android::bluetooth::audio::GetSoftwarePcmCapabilities();
-    if (db_pcm_capabilities.size() == 1) {
-      audio_capabilities.resize(1);
-      audio_capabilities[0].pcmCapabilities(db_pcm_capabilities[0]);
-    }
-  }
-  LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType)
-            << " supports " << audio_capabilities.size() << " codecs";
-  _hidl_cb(audio_capabilities);
-  return Void();
-}
-
-Return<void> BluetoothAudioProvidersFactory::getProviderCapabilities_2_1(
-    const V2_1::SessionType sessionType,
-    getProviderCapabilities_2_1_cb _hidl_cb) {
-  hidl_vec<V2_1::AudioCapabilities> audio_capabilities =
-      hidl_vec<V2_1::AudioCapabilities>(0);
-  if (sessionType == V2_1::SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
-    std::vector<CodecCapabilities> db_codec_capabilities =
-        android::bluetooth::audio::GetOffloadCodecCapabilities(sessionType);
-    if (db_codec_capabilities.size()) {
-      audio_capabilities.resize(db_codec_capabilities.size());
-      for (int i = 0; i < db_codec_capabilities.size(); ++i) {
-        audio_capabilities[i].codecCapabilities(db_codec_capabilities[i]);
-      }
-    }
-  } else if (sessionType != V2_1::SessionType::UNKNOWN) {
-    std::vector<V2_1::PcmParameters> db_pcm_capabilities =
-        android::bluetooth::audio::GetSoftwarePcmCapabilities_2_1();
-    if (db_pcm_capabilities.size() == 1) {
-      audio_capabilities.resize(1);
-      audio_capabilities[0].pcmCapabilities(db_pcm_capabilities[0]);
-    }
-  }
-  LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType)
-            << " supports " << audio_capabilities.size() << " codecs";
-  _hidl_cb(audio_capabilities);
-  return Void();
-}
-
-Return<void> BluetoothAudioProvidersFactory::getProviderCapabilities_2_2(
-    const V2_1::SessionType sessionType,
-    getProviderCapabilities_2_2_cb _hidl_cb) {
-  hidl_vec<V2_2::AudioCapabilities> audio_capabilities =
-      hidl_vec<V2_2::AudioCapabilities>(0);
-  if (sessionType == V2_1::SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
-    std::vector<CodecCapabilities> db_codec_capabilities =
-        android::bluetooth::audio::GetOffloadCodecCapabilities(sessionType);
-    if (db_codec_capabilities.size()) {
-      audio_capabilities.resize(db_codec_capabilities.size());
-      for (int i = 0; i < db_codec_capabilities.size(); ++i) {
-        audio_capabilities[i].codecCapabilities(db_codec_capabilities[i]);
-      }
-    }
-  } else if (sessionType == V2_1::SessionType::
-                                LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
-             sessionType == V2_1::SessionType::
-                                LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
-    std::vector<LeAudioCodecCapabilitiesSetting> db_codec_capabilities =
-        android::bluetooth::audio::GetLeAudioOffloadCodecCapabilities(
-            sessionType);
-    if (db_codec_capabilities.size()) {
-      audio_capabilities.resize(db_codec_capabilities.size());
-      for (int i = 0; i < db_codec_capabilities.size(); ++i) {
-        audio_capabilities[i].leAudioCapabilities(db_codec_capabilities[i]);
-      }
-    }
-  } else if (sessionType != V2_1::SessionType::UNKNOWN) {
-    std::vector<V2_1::PcmParameters> db_pcm_capabilities =
-        android::bluetooth::audio::GetSoftwarePcmCapabilities_2_1();
-    if (db_pcm_capabilities.size() == 1) {
-      audio_capabilities.resize(1);
-      audio_capabilities[0].pcmCapabilities(db_pcm_capabilities[0]);
-    }
-  }
-  LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType)
-            << " supports " << audio_capabilities.size() << " codecs";
-  _hidl_cb(audio_capabilities);
-  return Void();
-}
-
-IBluetoothAudioProvidersFactory* HIDL_FETCH_IBluetoothAudioProvidersFactory(
-    const char* /* name */) {
-  return new BluetoothAudioProvidersFactory();
-}
-
-}  // namespace implementation
-}  // namespace V2_2
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
diff --git a/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.h b/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.h
deleted file mode 100644
index 4f549d9..0000000
--- a/bluetooth/audio/2.2/default/BluetoothAudioProvidersFactory.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android/hardware/bluetooth/audio/2.2/IBluetoothAudioProvidersFactory.h>
-
-#include "A2dpOffloadAudioProvider.h"
-#include "A2dpSoftwareAudioProvider.h"
-#include "BluetoothAudioProvider.h"
-#include "HearingAidAudioProvider.h"
-#include "LeAudioAudioProvider.h"
-#include "LeAudioOffloadAudioProvider.h"
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace audio {
-namespace V2_2 {
-namespace implementation {
-
-class BluetoothAudioProvidersFactory : public IBluetoothAudioProvidersFactory {
- public:
-  BluetoothAudioProvidersFactory() {}
-
-  Return<void> openProvider(const V2_0::SessionType sessionType,
-                            openProvider_cb _hidl_cb) override;
-
-  Return<void> getProviderCapabilities(
-      const V2_0::SessionType sessionType,
-      getProviderCapabilities_cb _hidl_cb) override;
-
-  Return<void> openProvider_2_1(const V2_1::SessionType sessionType,
-                                openProvider_2_1_cb _hidl_cb) override;
-
-  Return<void> openProvider_2_2(const V2_1::SessionType sessionType,
-                                openProvider_2_2_cb _hidl_cb) override;
-
-  Return<void> getProviderCapabilities_2_1(
-      const V2_1::SessionType sessionType,
-      getProviderCapabilities_2_1_cb _hidl_cb) override;
-
-  Return<void> getProviderCapabilities_2_2(
-      const V2_1::SessionType sessionType,
-      getProviderCapabilities_2_2_cb _hidl_cb) override;
-
- private:
-  static A2dpSoftwareAudioProvider a2dp_software_provider_instance_;
-  static A2dpOffloadAudioProvider a2dp_offload_provider_instance_;
-  static HearingAidAudioProvider hearing_aid_provider_instance_;
-  static LeAudioOutputAudioProvider leaudio_output_provider_instance_;
-  static LeAudioInputAudioProvider leaudio_input_provider_instance_;
-  static LeAudioOffloadOutputAudioProvider
-      leaudio_offload_output_provider_instance_;
-  static LeAudioOffloadInputAudioProvider
-      leaudio_offload_input_provider_instance_;
-};
-
-extern "C" IBluetoothAudioProvidersFactory*
-HIDL_FETCH_IBluetoothAudioProvidersFactory(const char* name);
-
-}  // namespace implementation
-}  // namespace V2_2
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
diff --git a/bluetooth/audio/2.2/default/HearingAidAudioProvider.cpp b/bluetooth/audio/2.2/default/HearingAidAudioProvider.cpp
deleted file mode 100644
index 25e49a1..0000000
--- a/bluetooth/audio/2.2/default/HearingAidAudioProvider.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BTAudioProviderHearingAid"
-
-#include "HearingAidAudioProvider.h"
-
-#include <android-base/logging.h>
-
-#include "BluetoothAudioSessionReport_2_2.h"
-#include "BluetoothAudioSupportedCodecsDB_2_2.h"
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace audio {
-namespace V2_2 {
-namespace implementation {
-
-using ::android::bluetooth::audio::BluetoothAudioSessionReport_2_2;
-using ::android::hardware::Void;
-using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
-
-static constexpr uint32_t kPcmFrameSize = 4;  // 16 bits per sample / stereo
-static constexpr uint32_t kPcmFrameCount = 128;
-static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount;
-static constexpr uint32_t kRtpFrameCount = 7;  // max counts by 1 tick (20ms)
-static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount;
-static constexpr uint32_t kBufferCount = 1;  // single buffer
-static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount;
-
-HearingAidAudioProvider::HearingAidAudioProvider()
-    : BluetoothAudioProvider(), mDataMQ(nullptr) {
-  LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
-            << " byte(s)";
-  std::unique_ptr<DataMQ> tempDataMQ(
-      new DataMQ(kDataMqSize, /* EventFlag */ true));
-  if (tempDataMQ && tempDataMQ->isValid()) {
-    mDataMQ = std::move(tempDataMQ);
-    session_type_ = V2_1::SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH;
-  } else {
-    ALOGE_IF(!tempDataMQ, "failed to allocate data MQ");
-    ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "data MQ is invalid");
-  }
-}
-
-bool HearingAidAudioProvider::isValid(const V2_0::SessionType& sessionType) {
-  return isValid(static_cast<V2_1::SessionType>(sessionType));
-}
-
-bool HearingAidAudioProvider::isValid(const V2_1::SessionType& sessionType) {
-  return (sessionType == session_type_ && mDataMQ && mDataMQ->isValid());
-}
-
-Return<void> HearingAidAudioProvider::startSession(
-    const sp<V2_0::IBluetoothAudioPort>& hostIf,
-    const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
-  /**
-   * Initialize the audio platform if audioConfiguration is supported.
-   * Save the IBluetoothAudioPort interface, so that it can be used
-   * later to send stream control commands to the HAL client, based on
-   * interaction with Audio framework.
-   */
-  if (audioConfig.getDiscriminator() !=
-      AudioConfiguration::hidl_discriminator::pcmConfig) {
-    LOG(WARNING) << __func__
-                 << " - Invalid Audio Configuration=" << toString(audioConfig);
-    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
-             DataMQ::Descriptor());
-    return Void();
-  } else if (!android::bluetooth::audio::IsSoftwarePcmConfigurationValid(
-                 audioConfig.pcmConfig())) {
-    LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
-                 << toString(audioConfig.pcmConfig());
-    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
-             DataMQ::Descriptor());
-    return Void();
-  }
-
-  return BluetoothAudioProvider::startSession(hostIf, audioConfig, _hidl_cb);
-}
-
-Return<void> HearingAidAudioProvider::onSessionReady(startSession_cb _hidl_cb) {
-  if (mDataMQ && mDataMQ->isValid()) {
-    BluetoothAudioSessionReport_2_2::OnSessionStarted(
-        session_type_, stack_iface_, mDataMQ->getDesc(), audio_config_);
-    _hidl_cb(BluetoothAudioStatus::SUCCESS, *mDataMQ->getDesc());
-  } else {
-    _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
-  }
-  return Void();
-}
-
-}  // namespace implementation
-}  // namespace V2_2
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
diff --git a/bluetooth/audio/2.2/default/HearingAidAudioProvider.h b/bluetooth/audio/2.2/default/HearingAidAudioProvider.h
deleted file mode 100644
index 63290b5..0000000
--- a/bluetooth/audio/2.2/default/HearingAidAudioProvider.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <fmq/MessageQueue.h>
-#include <hidl/MQDescriptor.h>
-
-#include "BluetoothAudioProvider.h"
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace audio {
-namespace V2_2 {
-namespace implementation {
-
-using ::android::hardware::kSynchronizedReadWrite;
-using ::android::hardware::MessageQueue;
-
-using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
-
-class HearingAidAudioProvider : public BluetoothAudioProvider {
- public:
-  HearingAidAudioProvider();
-
-  bool isValid(const V2_1::SessionType& sessionType) override;
-  bool isValid(const V2_0::SessionType& sessionType) override;
-
-  Return<void> startSession(const sp<V2_0::IBluetoothAudioPort>& hostIf,
-                            const V2_0::AudioConfiguration& audioConfig,
-                            startSession_cb _hidl_cb) override;
-
- private:
-  // audio data queue for software encoding
-  std::unique_ptr<DataMQ> mDataMQ;
-
-  Return<void> onSessionReady(startSession_cb _hidl_cb) override;
-};
-
-}  // namespace implementation
-}  // namespace V2_2
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
diff --git a/bluetooth/audio/2.2/default/LeAudioAudioProvider.cpp b/bluetooth/audio/2.2/default/LeAudioAudioProvider.cpp
deleted file mode 100644
index a7a0023..0000000
--- a/bluetooth/audio/2.2/default/LeAudioAudioProvider.cpp
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BTAudioProviderLeAudio"
-
-#include "LeAudioAudioProvider.h"
-
-#include <android-base/logging.h>
-
-#include "AudioPort_2_0_to_2_2_Wrapper.h"
-#include "BluetoothAudioSessionReport_2_2.h"
-#include "BluetoothAudioSupportedCodecsDB_2_2.h"
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace audio {
-namespace V2_2 {
-namespace implementation {
-
-using ::android::bluetooth::audio::BluetoothAudioSessionReport_2_2;
-using ::android::hardware::Void;
-using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
-using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
-using ::android::hardware::bluetooth::audio::V2_1::SampleRate;
-
-static constexpr uint32_t kBufferOutCount = 2;  // two frame buffer
-static constexpr uint32_t kBufferInCount = 2;   // two frame buffer
-
-LeAudioOutputAudioProvider::LeAudioOutputAudioProvider()
-    : LeAudioAudioProvider() {
-  session_type_ = V2_1::SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH;
-}
-
-LeAudioInputAudioProvider::LeAudioInputAudioProvider()
-    : LeAudioAudioProvider() {
-  session_type_ = V2_1::SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH;
-}
-
-LeAudioAudioProvider::LeAudioAudioProvider()
-    : BluetoothAudioProvider(), mDataMQ(nullptr) {}
-
-bool LeAudioAudioProvider::isValid(const V2_0::SessionType& sessionType) {
-  LOG(ERROR) << __func__ << ", invalid session type for Le Audio provider: "
-             << toString(sessionType);
-
-  return false;
-}
-
-bool LeAudioAudioProvider::isValid(const V2_1::SessionType& sessionType) {
-  return (sessionType == session_type_);
-}
-
-Return<void> LeAudioAudioProvider::startSession_2_1(
-    const sp<V2_0::IBluetoothAudioPort>& hostIf,
-    const V2_1::AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
-  if (audioConfig.getDiscriminator() !=
-      V2_1::AudioConfiguration::hidl_discriminator::pcmConfig) {
-    LOG(WARNING) << __func__
-                 << " - Invalid Audio Configuration=" << toString(audioConfig);
-    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
-             DataMQ::Descriptor());
-    return Void();
-  }
-
-  AudioConfiguration audioConfig_2_2;
-  audioConfig_2_2.pcmConfig(
-      {.sampleRate =
-           static_cast<V2_1::SampleRate>(audioConfig.pcmConfig().sampleRate),
-       .channelMode = audioConfig.pcmConfig().channelMode,
-       .bitsPerSample = audioConfig.pcmConfig().bitsPerSample,
-       .dataIntervalUs = 0});
-
-  sp<V2_2::IBluetoothAudioPort> hostIf_2_2 =
-      new AudioPort_2_0_to_2_2_Wrapper(hostIf);
-  return startSession_2_2(hostIf_2_2, audioConfig_2_2, _hidl_cb);
-}
-
-Return<void> LeAudioAudioProvider::startSession_2_2(
-    const sp<V2_2::IBluetoothAudioPort>& hostIf,
-    const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
-  /**
-   * Initialize the audio platform if audioConfiguration is supported.
-   * Save the IBluetoothAudioPort interface, so that it can be used
-   * later to send stream control commands to the HAL client, based on
-   * interaction with Audio framework.
-   */
-  if (audioConfig.getDiscriminator() !=
-      AudioConfiguration::hidl_discriminator::pcmConfig) {
-    LOG(WARNING) << __func__
-                 << " - Invalid Audio Configuration=" << toString(audioConfig);
-    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
-             DataMQ::Descriptor());
-    return Void();
-  } else if (!android::bluetooth::audio::IsSoftwarePcmConfigurationValid_2_1(
-                 audioConfig.pcmConfig())) {
-    LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
-                 << toString(audioConfig.pcmConfig());
-    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
-             DataMQ::Descriptor());
-    return Void();
-  }
-
-  uint32_t kDataMqSize = 0;
-  switch (audioConfig.pcmConfig().sampleRate) {
-    case SampleRate::RATE_8000:
-      kDataMqSize = 8000;
-      break;
-    case SampleRate::RATE_16000:
-      kDataMqSize = 16000;
-      break;
-    case SampleRate::RATE_24000:
-      kDataMqSize = 24000;
-      break;
-    case SampleRate::RATE_32000:
-      kDataMqSize = 32000;
-      break;
-    case SampleRate::RATE_44100:
-      kDataMqSize = 44100;
-      break;
-    case SampleRate::RATE_48000:
-      kDataMqSize = 48000;
-      break;
-    default:
-      LOG(WARNING) << __func__ << " - Unsupported sampling frequency="
-                   << toString(audioConfig.pcmConfig());
-      _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
-               DataMQ::Descriptor());
-      return Void();
-  }
-
-  /* Number of samples per millisecond */
-  kDataMqSize = ceil(kDataMqSize / 1000);
-
-  switch (audioConfig.pcmConfig().channelMode) {
-    case ChannelMode::MONO:
-      break;
-    case ChannelMode::STEREO:
-      kDataMqSize *= 2;
-      break;
-    default:
-      /* This should never happen it would be caught while validating
-       * parameters.
-       */
-      break;
-  }
-
-  switch (audioConfig.pcmConfig().bitsPerSample) {
-    case BitsPerSample::BITS_16:
-      kDataMqSize *= 2;
-      break;
-    case BitsPerSample::BITS_24:
-      kDataMqSize *= 3;
-      break;
-    case BitsPerSample::BITS_32:
-      kDataMqSize *= 4;
-      break;
-    default:
-      /* This should never happen it would be caught while validating
-       * parameters.
-       */
-      break;
-  }
-
-  if (session_type_ == V2_1::SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH)
-    kDataMqSize *= kBufferOutCount;
-  else if (session_type_ ==
-           V2_1::SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH)
-    kDataMqSize *= kBufferInCount;
-  else
-    LOG(WARNING) << __func__ << ", default single buffer used";
-
-  kDataMqSize *= audioConfig.pcmConfig().dataIntervalUs / 1000;
-
-  LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
-            << " byte(s)";
-
-  std::unique_ptr<DataMQ> tempDataMQ(
-      new DataMQ(kDataMqSize, /* EventFlag */ true));
-  if (tempDataMQ && tempDataMQ->isValid()) {
-    mDataMQ = std::move(tempDataMQ);
-  } else {
-    ALOGE_IF(!tempDataMQ, "failed to allocate data MQ");
-    ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "data MQ is invalid");
-    _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
-    return Void();
-  }
-
-  return BluetoothAudioProvider::startSession_2_2(hostIf, audioConfig,
-                                                  _hidl_cb);
-}
-
-Return<void> LeAudioAudioProvider::onSessionReady(startSession_cb _hidl_cb) {
-  if (mDataMQ && mDataMQ->isValid()) {
-    BluetoothAudioSessionReport_2_2::OnSessionStarted(
-        session_type_, stack_iface_, mDataMQ->getDesc(), audio_config_);
-    _hidl_cb(BluetoothAudioStatus::SUCCESS, *mDataMQ->getDesc());
-  } else {
-    _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
-  }
-  return Void();
-}
-
-}  // namespace implementation
-}  // namespace V2_2
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
diff --git a/bluetooth/audio/2.2/default/LeAudioAudioProvider.h b/bluetooth/audio/2.2/default/LeAudioAudioProvider.h
deleted file mode 100644
index 3de1724..0000000
--- a/bluetooth/audio/2.2/default/LeAudioAudioProvider.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android/hardware/bluetooth/audio/2.2/types.h>
-#include <fmq/MessageQueue.h>
-#include <hidl/MQDescriptor.h>
-
-#include "BluetoothAudioProvider.h"
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace audio {
-namespace V2_2 {
-namespace implementation {
-
-using ::android::hardware::kSynchronizedReadWrite;
-using ::android::hardware::MessageQueue;
-
-using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
-
-class LeAudioAudioProvider : public BluetoothAudioProvider {
- public:
-  LeAudioAudioProvider();
-
-  bool isValid(const V2_1::SessionType& sessionType) override;
-  bool isValid(const V2_0::SessionType& sessionType) override;
-
-  Return<void> startSession_2_1(const sp<V2_0::IBluetoothAudioPort>& hostIf,
-                                const V2_1::AudioConfiguration& audioConfig,
-                                startSession_cb _hidl_cb) override;
-
-  Return<void> startSession_2_2(const sp<V2_2::IBluetoothAudioPort>& hostIf,
-                                const AudioConfiguration& audioConfig,
-                                startSession_cb _hidl_cb) override;
-
- private:
-  /** queue for software encodec/decoded audio data */
-  std::unique_ptr<DataMQ> mDataMQ;
-
-  Return<void> onSessionReady(startSession_cb _hidl_cb) override;
-};
-
-class LeAudioOutputAudioProvider : public LeAudioAudioProvider {
- public:
-  LeAudioOutputAudioProvider();
-};
-
-class LeAudioInputAudioProvider : public LeAudioAudioProvider {
- public:
-  LeAudioInputAudioProvider();
-};
-
-}  // namespace implementation
-}  // namespace V2_2
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
diff --git a/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.cpp
deleted file mode 100644
index 2b0c02f..0000000
--- a/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BTAudioProviderLeAudioOffload"
-
-#include "LeAudioOffloadAudioProvider.h"
-
-#include <android-base/logging.h>
-
-#include "AudioPort_2_0_to_2_2_Wrapper.h"
-#include "BluetoothAudioSessionReport_2_2.h"
-#include "BluetoothAudioSupportedCodecsDB_2_2.h"
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace audio {
-namespace V2_2 {
-namespace implementation {
-
-using ::android::bluetooth::audio::BluetoothAudioSessionReport_2_2;
-using ::android::hardware::Void;
-using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
-using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
-using ::android::hardware::bluetooth::audio::V2_1::SampleRate;
-
-using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
-
-LeAudioOffloadOutputAudioProvider::LeAudioOffloadOutputAudioProvider()
-    : LeAudioOffloadAudioProvider() {
-  session_type_ =
-      V2_1::SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
-}
-
-LeAudioOffloadInputAudioProvider::LeAudioOffloadInputAudioProvider()
-    : LeAudioOffloadAudioProvider() {
-  session_type_ =
-      V2_1::SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH;
-}
-
-LeAudioOffloadAudioProvider::LeAudioOffloadAudioProvider()
-    : BluetoothAudioProvider() {}
-
-bool LeAudioOffloadAudioProvider::isValid(
-    const V2_0::SessionType& sessionType) {
-  LOG(ERROR) << __func__
-             << ", invalid session type for Offloaded Le Audio provider: "
-             << toString(sessionType);
-
-  return false;
-}
-
-bool LeAudioOffloadAudioProvider::isValid(
-    const V2_1::SessionType& sessionType) {
-  return (sessionType == session_type_);
-}
-
-Return<void> LeAudioOffloadAudioProvider::startSession_2_1(
-    const sp<V2_0::IBluetoothAudioPort>& hostIf,
-    const V2_1::AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
-  if (audioConfig.getDiscriminator() !=
-      V2_1::AudioConfiguration::hidl_discriminator::leAudioCodecConfig) {
-    LOG(WARNING) << __func__
-                 << " - Invalid Audio Configuration=" << toString(audioConfig);
-    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
-             DataMQ::Descriptor());
-    return Void();
-  }
-
-  AudioConfiguration audioConfig_2_2;
-  audioConfig_2_2.leAudioConfig().mode = LeAudioMode::UNKNOWN;
-  audioConfig_2_2.leAudioConfig().config.unicastConfig() = {
-      .streamMap = {{
-          .streamHandle = 0xFFFF,
-          .audioChannelAllocation =
-              audioConfig.leAudioCodecConfig().audioChannelAllocation,
-      }},
-      .peerDelay = 0,
-      .lc3Config = audioConfig.leAudioCodecConfig().lc3Config};
-
-  sp<V2_2::IBluetoothAudioPort> hostIf_2_2 =
-      new AudioPort_2_0_to_2_2_Wrapper(hostIf);
-  return startSession_2_2(hostIf_2_2, audioConfig_2_2, _hidl_cb);
-}
-
-Return<void> LeAudioOffloadAudioProvider::startSession_2_2(
-    const sp<V2_2::IBluetoothAudioPort>& hostIf,
-    const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
-  /**
-   * Initialize the audio platform if audioConfiguration is supported.
-   * Save the IBluetoothAudioPort interface, so that it can be used
-   * later to send stream control commands to the HAL client, based on
-   * interaction with Audio framework.
-   */
-  if (audioConfig.getDiscriminator() !=
-      AudioConfiguration::hidl_discriminator::leAudioConfig) {
-    LOG(WARNING) << __func__
-                 << " - Invalid Audio Configuration=" << toString(audioConfig);
-    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
-             DataMQ::Descriptor());
-    return Void();
-  }
-
-  if (!android::bluetooth::audio::IsOffloadLeAudioConfigurationValid(
-          session_type_, audioConfig.leAudioConfig())) {
-    LOG(WARNING) << __func__ << " - Unsupported LC3 Offloaded Configuration="
-                 << toString(audioConfig.leAudioConfig());
-    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
-             DataMQ::Descriptor());
-    return Void();
-  }
-
-  return BluetoothAudioProvider::startSession_2_2(hostIf, audioConfig,
-                                                  _hidl_cb);
-}
-
-Return<void> LeAudioOffloadAudioProvider::onSessionReady(
-    startSession_cb _hidl_cb) {
-  BluetoothAudioSessionReport_2_2::OnSessionStarted(session_type_, stack_iface_,
-                                                    nullptr, audio_config_);
-  _hidl_cb(BluetoothAudioStatus::SUCCESS, DataMQ::Descriptor());
-  return Void();
-}
-
-}  // namespace implementation
-}  // namespace V2_2
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
diff --git a/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.h
deleted file mode 100644
index fe58de5..0000000
--- a/bluetooth/audio/2.2/default/LeAudioOffloadAudioProvider.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android/hardware/bluetooth/audio/2.2/types.h>
-
-#include "BluetoothAudioProvider.h"
-
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace audio {
-namespace V2_2 {
-namespace implementation {
-
-class LeAudioOffloadAudioProvider : public BluetoothAudioProvider {
- public:
-  LeAudioOffloadAudioProvider();
-
-  bool isValid(const V2_1::SessionType& sessionType) override;
-  bool isValid(const V2_0::SessionType& sessionType) override;
-
-  Return<void> startSession_2_1(const sp<V2_0::IBluetoothAudioPort>& hostIf,
-                                const V2_1::AudioConfiguration& audioConfig,
-                                startSession_cb _hidl_cb) override;
-
-  Return<void> startSession_2_2(const sp<V2_2::IBluetoothAudioPort>& hostIf,
-                                const AudioConfiguration& audioConfig,
-                                startSession_cb _hidl_cb) override;
-
- private:
-  Return<void> onSessionReady(startSession_cb _hidl_cb) override;
-};
-
-class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
- public:
-  LeAudioOffloadOutputAudioProvider();
-};
-
-class LeAudioOffloadInputAudioProvider : public LeAudioOffloadAudioProvider {
- public:
-  LeAudioOffloadInputAudioProvider();
-};
-
-}  // namespace implementation
-}  // namespace V2_2
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
diff --git a/bluetooth/audio/2.2/default/OWNERS b/bluetooth/audio/2.2/default/OWNERS
deleted file mode 100644
index 17ea464..0000000
--- a/bluetooth/audio/2.2/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-include platform/packages/modules/Bluetooth:/OWNERS
-
-cheneyni@google.com
-aliceypkuo@google.com
\ No newline at end of file
diff --git a/bluetooth/audio/2.2/types.hal b/bluetooth/audio/2.2/types.hal
deleted file mode 100644
index 6755899..0000000
--- a/bluetooth/audio/2.2/types.hal
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.bluetooth.audio@2.2;
-
-import @2.1::Lc3Parameters;
-import @2.1::PcmParameters;
-import @2.0::CodecConfiguration;
-import @2.0::CodecCapabilities;
-import @2.1::CodecType;
-
-enum LeAudioMode : uint8_t {
-    UNKNOWN = 0x00,
-    UNICAST = 0x01,
-    BROADCAST = 0x02,
-};
-
-enum AudioLocation : uint8_t {
-  UNKNOWN = 0,
-  FRONT_LEFT = 1,
-  FRONT_RIGHT = 2,
-};
-
-struct UnicastStreamMap {
-    /* The connection handle used for a unicast or a broadcast group. */
-    uint16_t streamHandle;
-    /* Audio channel allocation is  a bit field, each enabled bit means that given audio direction,
-     * i.e. "left", or "right" is used. Ordering of audio channels comes from the least significant
-     * bit to the most significant bit. */
-    uint32_t audioChannelAllocation;
-};
-
-struct BroadcastStreamMap {
-    /* The connection handle used for a unicast or a broadcast group. */
-    uint16_t streamHandle;
-    /* Audio channel allocation is  a bit field, each enabled bit means that given audio direction,
-     * i.e. "left", or "right" is used. Ordering of audio channels comes from the least significant
-     * bit to the most significant bit. */
-    uint32_t audioChannelAllocation;
-    Lc3Parameters lc3Config;
-};
-
-struct UnicastConfig {
-    vec<UnicastStreamMap> streamMap;
-    uint32_t peerDelay;
-    Lc3Parameters lc3Config;
-};
-
-struct BroadcastConfig {
-    vec<BroadcastStreamMap> streamMap;
-};
-
-struct LeAudioConfiguration {
-    /* The mode of the LE audio */
-    LeAudioMode mode;
-    safe_union CodecConfig {
-        UnicastConfig unicastConfig;
-        BroadcastConfig broadcastConfig;
-    } config;
-};
-
-/** Used to configure either a Hardware or Software Encoding session based on session type */
-safe_union AudioConfiguration {
-    PcmParameters pcmConfig;
-    CodecConfiguration codecConfig;
-    LeAudioConfiguration leAudioConfig;
-};
-
-/** Used to specify the capabilities of the different session types */
-safe_union AudioCapabilities {
-    PcmParameters pcmCapabilities;
-    CodecCapabilities codecCapabilities;
-    LeAudioCodecCapabilitiesSetting leAudioCapabilities;
-};
-
-/**
- * Used to specify the le audio capabilities for unicast and broadcast hardware offload.
- */
-struct LeAudioCodecCapabilitiesSetting{
-    UnicastCapability unicastEncodeCapability;
-    UnicastCapability unicastDecodeCapability;
-    BroadcastCapability broadcastCapability;
-};
-
-/**
- * Used to specify the le audio unicast codec capabilities for hardware offload.
- */
-struct UnicastCapability {
-    CodecType codecType;
-    AudioLocation supportedChannel;
-
-    // The number of connected device
-    uint8_t deviceCount;
-
-    // Supported channel count for each device
-    uint8_t channelCountPerDevice;
-
-    // Should use safe union when there is more than one codec
-    Lc3Parameters capabilities;
-};
-
-/**
- * Used to specify the le audio broadcast codec capabilities for hardware offload.
- */
-struct BroadcastCapability {
-    CodecType codecType;
-    AudioLocation supportedChannel;
-
-    // Supported channel count for each stream
-    uint8_t channelCountPerStream;
-
-    // Should use safe union when there is more than one codec
-    vec<Lc3Parameters> capabilities;
-};
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl
index cc3c641..d364371 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl
@@ -35,11 +35,10 @@
 @VintfStability
 interface IBluetoothAudioPort {
   android.hardware.bluetooth.audio.PresentationPosition getPresentationPosition();
-  void startStream();
+  void startStream(boolean isLowLatency);
   void stopStream();
   void suspendStream();
   void updateSourceMetadata(in android.hardware.audio.common.SourceMetadata sourceMetadata);
   void updateSinkMetadata(in android.hardware.audio.common.SinkMetadata sinkMetadata);
   void setLatencyMode(in android.hardware.bluetooth.audio.LatencyMode latencyMode);
-  void setCodecType(in android.hardware.bluetooth.audio.CodecType codecType);
 }
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
index 6e0bd98..267af0f 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
@@ -35,7 +35,7 @@
 @VintfStability
 interface IBluetoothAudioProvider {
   void endSession();
-  android.hardware.common.fmq.MQDescriptor<byte,android.hardware.common.fmq.SynchronizedReadWrite> startSession(in android.hardware.bluetooth.audio.IBluetoothAudioPort hostIf, in android.hardware.bluetooth.audio.AudioConfiguration audioConfig);
+  android.hardware.common.fmq.MQDescriptor<byte,android.hardware.common.fmq.SynchronizedReadWrite> startSession(in android.hardware.bluetooth.audio.IBluetoothAudioPort hostIf, in android.hardware.bluetooth.audio.AudioConfiguration audioConfig, in android.hardware.bluetooth.audio.LatencyMode[] supportedLatencyModes);
   void streamStarted(in android.hardware.bluetooth.audio.BluetoothAudioStatus status);
   void streamSuspended(in android.hardware.bluetooth.audio.BluetoothAudioStatus status);
   void updateAudioConfiguration(in android.hardware.bluetooth.audio.AudioConfiguration audioConfig);
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl
index 81c2ce2..4ddf645 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl
@@ -47,8 +47,11 @@
      * This indicates that the caller of this method has opened the data path
      * and wants to start an audio stream. The caller must wait for a
      * IBluetoothAudioProvider.streamStarted(Status) call.
+     *
+     * @param isLowLatency true if the stream being started with the latency
+     * control mechanism.
      */
-    void startStream();
+    void startStream(boolean isLowLatency);
 
     /**
      * This indicates that the caller of this method wants to stop the audio
@@ -87,11 +90,4 @@
      * @param latencyMode latency mode from audio
      */
     void setLatencyMode(in LatencyMode latencyMode);
-
-    /**
-     * Called when codec type is changed.
-     *
-     * @param codecType codec type from audio
-     */
-    void setCodecType(in CodecType codecType);
 }
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
index ca6f691..d5c051e 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioProvider.aidl
@@ -19,6 +19,7 @@
 import android.hardware.bluetooth.audio.AudioConfiguration;
 import android.hardware.bluetooth.audio.BluetoothAudioStatus;
 import android.hardware.bluetooth.audio.IBluetoothAudioPort;
+import android.hardware.bluetooth.audio.LatencyMode;
 import android.hardware.common.fmq.MQDescriptor;
 import android.hardware.common.fmq.SynchronizedReadWrite;
 
@@ -50,6 +51,8 @@
      *    device. The PCM parameters are set if software based encoding,
      *    otherwise the correct codec configuration is used for hardware
      *    encoding.
+     * @param supportedLatencyModes latency modes supported by the active
+     * remote device
      *
      * @return The fast message queue for audio data from/to this
      *    provider. Audio data will be in PCM format as specified by the
@@ -57,8 +60,8 @@
      *    from/to hardware or on failure
      */
     MQDescriptor<byte, SynchronizedReadWrite> startSession(
-            in IBluetoothAudioPort hostIf, in AudioConfiguration audioConfig);
-
+            in IBluetoothAudioPort hostIf, in AudioConfiguration audioConfig,
+            in LatencyMode[] supportedLatencyModes);
     /**
      * Callback for IBluetoothAudioPort.startStream()
      *
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
index fc8a911..4b4713d 100644
--- a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.cpp
@@ -38,7 +38,8 @@
 
 ndk::ScopedAStatus A2dpOffloadAudioProvider::startSession(
     const std::shared_ptr<IBluetoothAudioPort>& host_if,
-    const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+    const AudioConfiguration& audio_config,
+    const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
   if (audio_config.getTag() != AudioConfiguration::a2dpConfig) {
     LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
                  << audio_config.toString();
@@ -52,15 +53,15 @@
     *_aidl_return = DataMQDesc();
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
   }
-  return BluetoothAudioProvider::startSession(host_if, audio_config,
-                                              _aidl_return);
+  return BluetoothAudioProvider::startSession(
+      host_if, audio_config, latency_modes, _aidl_return);
 }
 
 ndk::ScopedAStatus A2dpOffloadAudioProvider::onSessionReady(
     DataMQDesc* _aidl_return) {
   *_aidl_return = DataMQDesc();
-  BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
-                                                nullptr, *audio_config_);
+  BluetoothAudioSessionReport::OnSessionStarted(
+      session_type_, stack_iface_, nullptr, *audio_config_, latency_modes_);
   return ndk::ScopedAStatus::ok();
 }
 
@@ -68,4 +69,4 @@
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
-}  // namespace aidl
\ No newline at end of file
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h
index 5934f5b..4621e85 100644
--- a/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h
+++ b/bluetooth/audio/aidl/default/A2dpOffloadAudioProvider.h
@@ -32,7 +32,9 @@
 
   ndk::ScopedAStatus startSession(
       const std::shared_ptr<IBluetoothAudioPort>& host_if,
-      const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+      const AudioConfiguration& audio_config,
+      const std::vector<LatencyMode>& latency_modes,
+      DataMQDesc* _aidl_return);
 
  private:
   ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
diff --git a/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.cpp b/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.cpp
index 5a413e0..59df3a9 100644
--- a/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.cpp
@@ -61,7 +61,8 @@
 
 ndk::ScopedAStatus A2dpSoftwareAudioProvider::startSession(
     const std::shared_ptr<IBluetoothAudioPort>& host_if,
-    const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+    const AudioConfiguration& audio_config,
+    const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
   if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
     LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
                  << audio_config.toString();
@@ -77,8 +78,8 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
   }
 
-  return BluetoothAudioProvider::startSession(host_if, audio_config,
-                                              _aidl_return);
+  return BluetoothAudioProvider::startSession(
+      host_if, audio_config, latency_modes, _aidl_return);
 }
 
 ndk::ScopedAStatus A2dpSoftwareAudioProvider::onSessionReady(
@@ -89,8 +90,8 @@
   }
   *_aidl_return = data_mq_->dupeDesc();
   auto desc = data_mq_->dupeDesc();
-  BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
-                                                &desc, *audio_config_);
+  BluetoothAudioSessionReport::OnSessionStarted(
+      session_type_, stack_iface_, &desc, *audio_config_, latency_modes_);
   return ndk::ScopedAStatus::ok();
 }
 
@@ -98,4 +99,4 @@
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
-}  // namespace aidl
\ No newline at end of file
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.h b/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.h
index 3bc0a13..10f533a 100644
--- a/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.h
+++ b/bluetooth/audio/aidl/default/A2dpSoftwareAudioProvider.h
@@ -32,7 +32,9 @@
 
   ndk::ScopedAStatus startSession(
       const std::shared_ptr<IBluetoothAudioPort>& host_if,
-      const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+      const AudioConfiguration& audio_config,
+      const std::vector<LatencyMode>& latency_modes,
+      DataMQDesc* _aidl_return);
 
  private:
   // audio data queue for software encoding
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
index 8090d26..0dd8148 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
@@ -34,11 +34,15 @@
 
 ndk::ScopedAStatus BluetoothAudioProvider::startSession(
     const std::shared_ptr<IBluetoothAudioPort>& host_if,
-    const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+    const AudioConfiguration& audio_config,
+    const std::vector<LatencyMode>& latencyModes,
+    DataMQDesc* _aidl_return) {
   if (host_if == nullptr) {
     *_aidl_return = DataMQDesc();
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
   }
+
+  latency_modes_ = latencyModes;
   audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
   stack_iface_ = host_if;
 
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.h b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
index 393aaba..a9f830a 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
@@ -16,6 +16,7 @@
 #pragma once
 
 #include <aidl/android/hardware/bluetooth/audio/BnBluetoothAudioProvider.h>
+#include <aidl/android/hardware/bluetooth/audio/LatencyMode.h>
 #include <aidl/android/hardware/bluetooth/audio/SessionType.h>
 #include <fmq/AidlMessageQueue.h>
 
@@ -37,10 +38,11 @@
 class BluetoothAudioProvider : public BnBluetoothAudioProvider {
  public:
   BluetoothAudioProvider();
-
   ndk::ScopedAStatus startSession(
       const std::shared_ptr<IBluetoothAudioPort>& host_if,
-      const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+      const AudioConfiguration& audio_config,
+      const std::vector<LatencyMode>& latency_modes,
+      DataMQDesc* _aidl_return);
   ndk::ScopedAStatus endSession();
   ndk::ScopedAStatus streamStarted(BluetoothAudioStatus status);
   ndk::ScopedAStatus streamSuspended(BluetoothAudioStatus status);
@@ -59,10 +61,11 @@
   std::shared_ptr<IBluetoothAudioPort> stack_iface_;
   std::unique_ptr<AudioConfiguration> audio_config_ = nullptr;
   SessionType session_type_;
+  std::vector<LatencyMode> latency_modes_;
 };
 
 }  // namespace audio
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
-}  // namespace aidl
\ No newline at end of file
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/HearingAidAudioProvider.cpp b/bluetooth/audio/aidl/default/HearingAidAudioProvider.cpp
index 66ce93b..e8b01ac 100644
--- a/bluetooth/audio/aidl/default/HearingAidAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/HearingAidAudioProvider.cpp
@@ -56,7 +56,8 @@
 
 ndk::ScopedAStatus HearingAidAudioProvider::startSession(
     const std::shared_ptr<IBluetoothAudioPort>& host_if,
-    const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+    const AudioConfiguration& audio_config,
+    const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
   if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
     LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
                  << audio_config.toString();
@@ -71,8 +72,8 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
   }
 
-  return BluetoothAudioProvider::startSession(host_if, audio_config,
-                                              _aidl_return);
+  return BluetoothAudioProvider::startSession(
+      host_if, audio_config, latency_modes, _aidl_return);
 }
 
 ndk::ScopedAStatus HearingAidAudioProvider::onSessionReady(
@@ -83,8 +84,8 @@
   }
   *_aidl_return = data_mq_->dupeDesc();
   auto desc = data_mq_->dupeDesc();
-  BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
-                                                &desc, *audio_config_);
+  BluetoothAudioSessionReport::OnSessionStarted(
+      session_type_, stack_iface_, &desc, *audio_config_, latency_modes_);
   return ndk::ScopedAStatus::ok();
 }
 
@@ -92,4 +93,4 @@
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
-}  // namespace aidl
\ No newline at end of file
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/HearingAidAudioProvider.h b/bluetooth/audio/aidl/default/HearingAidAudioProvider.h
index a7e19e9..a158c86 100644
--- a/bluetooth/audio/aidl/default/HearingAidAudioProvider.h
+++ b/bluetooth/audio/aidl/default/HearingAidAudioProvider.h
@@ -32,7 +32,9 @@
 
   ndk::ScopedAStatus startSession(
       const std::shared_ptr<IBluetoothAudioPort>& host_if,
-      const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+      const AudioConfiguration& audio_config,
+      const std::vector<LatencyMode>& latency_modes,
+      DataMQDesc* _aidl_return);
 
  private:
   // audio data queue for software encoding
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
index 7a28513..0e22e44 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
@@ -53,7 +53,8 @@
 
 ndk::ScopedAStatus LeAudioOffloadAudioProvider::startSession(
     const std::shared_ptr<IBluetoothAudioPort>& host_if,
-    const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+    const AudioConfiguration& audio_config,
+    const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
   if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
     LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
                  << audio_config.toString();
@@ -70,14 +71,14 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
   }
 
-  return BluetoothAudioProvider::startSession(host_if, audio_config,
-                                              _aidl_return);
+  return BluetoothAudioProvider::startSession(
+      host_if, audio_config, latency_modes, _aidl_return);
 }
 
 ndk::ScopedAStatus LeAudioOffloadAudioProvider::onSessionReady(
     DataMQDesc* _aidl_return) {
-  BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
-                                                nullptr, *audio_config_);
+  BluetoothAudioSessionReport::OnSessionStarted(
+      session_type_, stack_iface_, nullptr, *audio_config_, latency_modes_);
   *_aidl_return = DataMQDesc();
   return ndk::ScopedAStatus::ok();
 }
@@ -86,4 +87,4 @@
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
-}  // namespace aidl
\ No newline at end of file
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
index 6509a9e..614c794 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
@@ -32,7 +32,9 @@
 
   ndk::ScopedAStatus startSession(
       const std::shared_ptr<IBluetoothAudioPort>& host_if,
-      const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+      const AudioConfiguration& audio_config,
+      const std::vector<LatencyMode>& latency_modes,
+      DataMQDesc* _aidl_return);
 
  private:
   ndk::ScopedAStatus onSessionReady(DataMQDesc* _aidl_return) override;
diff --git a/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
index 0fe205e..911c928 100644
--- a/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.cpp
@@ -69,7 +69,8 @@
 
 ndk::ScopedAStatus LeAudioSoftwareAudioProvider::startSession(
     const std::shared_ptr<IBluetoothAudioPort>& host_if,
-    const AudioConfiguration& audio_config, DataMQDesc* _aidl_return) {
+    const AudioConfiguration& audio_config,
+    const std::vector<LatencyMode>& latency_modes, DataMQDesc* _aidl_return) {
   if (audio_config.getTag() != AudioConfiguration::pcmConfig) {
     LOG(WARNING) << __func__ << " - Invalid Audio Configuration="
                  << audio_config.toString();
@@ -119,8 +120,8 @@
   }
   data_mq_ = std::move(temp_data_mq);
 
-  return BluetoothAudioProvider::startSession(host_if, audio_config,
-                                              _aidl_return);
+  return BluetoothAudioProvider::startSession(
+      host_if, audio_config, latency_modes, _aidl_return);
 }
 
 ndk::ScopedAStatus LeAudioSoftwareAudioProvider::onSessionReady(
@@ -131,8 +132,8 @@
   }
   *_aidl_return = data_mq_->dupeDesc();
   auto desc = data_mq_->dupeDesc();
-  BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
-                                                &desc, *audio_config_);
+  BluetoothAudioSessionReport::OnSessionStarted(
+      session_type_, stack_iface_, &desc, *audio_config_, latency_modes_);
   return ndk::ScopedAStatus::ok();
 }
 
@@ -140,4 +141,4 @@
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
-}  // namespace aidl
\ No newline at end of file
+}  // namespace aidl
diff --git a/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.h
index ace4bff..21243ff 100644
--- a/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.h
+++ b/bluetooth/audio/aidl/default/LeAudioSoftwareAudioProvider.h
@@ -32,7 +32,9 @@
 
   ndk::ScopedAStatus startSession(
       const std::shared_ptr<IBluetoothAudioPort>& host_if,
-      const AudioConfiguration& audio_config, DataMQDesc* _aidl_return);
+      const AudioConfiguration& audio_config,
+      const std::vector<LatencyMode>& latency_modes,
+      DataMQDesc* _aidl_return);
 
  private:
   // audio data queue for software encoding
diff --git a/bluetooth/audio/aidl/vts/Android.bp b/bluetooth/audio/aidl/vts/Android.bp
new file mode 100644
index 0000000..feb952e
--- /dev/null
+++ b/bluetooth/audio/aidl/vts/Android.bp
@@ -0,0 +1,32 @@
+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_test {
+    name: "VtsHalBluetoothAudioTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    tidy_timeout_srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
+    srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
+    shared_libs: [
+        "android.hardware.audio.common-V1-ndk",
+        "android.hardware.bluetooth.audio-V1-ndk",
+        "android.hardware.common-V2-ndk",
+        "android.hardware.common.fmq-V1-ndk",
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "libfmq",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
new file mode 100644
index 0000000..18352a0
--- /dev/null
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -0,0 +1,1673 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/bluetooth/audio/BnBluetoothAudioPort.h>
+#include <aidl/android/hardware/bluetooth/audio/IBluetoothAudioPort.h>
+#include <aidl/android/hardware/bluetooth/audio/IBluetoothAudioProviderFactory.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include <cstdint>
+#include <future>
+#include <unordered_set>
+#include <vector>
+
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::bluetooth::audio::AacCapabilities;
+using aidl::android::hardware::bluetooth::audio::AacConfiguration;
+using aidl::android::hardware::bluetooth::audio::AptxCapabilities;
+using aidl::android::hardware::bluetooth::audio::AptxConfiguration;
+using aidl::android::hardware::bluetooth::audio::AudioCapabilities;
+using aidl::android::hardware::bluetooth::audio::AudioConfiguration;
+using aidl::android::hardware::bluetooth::audio::BnBluetoothAudioPort;
+using aidl::android::hardware::bluetooth::audio::BroadcastCapability;
+using aidl::android::hardware::bluetooth::audio::ChannelMode;
+using aidl::android::hardware::bluetooth::audio::CodecCapabilities;
+using aidl::android::hardware::bluetooth::audio::CodecConfiguration;
+using aidl::android::hardware::bluetooth::audio::CodecType;
+using aidl::android::hardware::bluetooth::audio::IBluetoothAudioPort;
+using aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider;
+using aidl::android::hardware::bluetooth::audio::IBluetoothAudioProviderFactory;
+using aidl::android::hardware::bluetooth::audio::LatencyMode;
+using aidl::android::hardware::bluetooth::audio::Lc3Capabilities;
+using aidl::android::hardware::bluetooth::audio::Lc3Configuration;
+using aidl::android::hardware::bluetooth::audio::LdacCapabilities;
+using aidl::android::hardware::bluetooth::audio::LdacConfiguration;
+using aidl::android::hardware::bluetooth::audio::LeAudioBroadcastConfiguration;
+using aidl::android::hardware::bluetooth::audio::
+    LeAudioCodecCapabilitiesSetting;
+using aidl::android::hardware::bluetooth::audio::LeAudioCodecConfiguration;
+using aidl::android::hardware::bluetooth::audio::LeAudioConfiguration;
+using aidl::android::hardware::bluetooth::audio::PcmConfiguration;
+using aidl::android::hardware::bluetooth::audio::PresentationPosition;
+using aidl::android::hardware::bluetooth::audio::SbcAllocMethod;
+using aidl::android::hardware::bluetooth::audio::SbcCapabilities;
+using aidl::android::hardware::bluetooth::audio::SbcChannelMode;
+using aidl::android::hardware::bluetooth::audio::SbcConfiguration;
+using aidl::android::hardware::bluetooth::audio::SessionType;
+using aidl::android::hardware::bluetooth::audio::UnicastCapability;
+using aidl::android::hardware::common::fmq::MQDescriptor;
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using android::AidlMessageQueue;
+using android::ProcessState;
+using android::String16;
+using ndk::ScopedAStatus;
+using ndk::SpAIBinder;
+
+using MqDataType = int8_t;
+using MqDataMode = SynchronizedReadWrite;
+using DataMQ = AidlMessageQueue<MqDataType, MqDataMode>;
+using DataMQDesc = MQDescriptor<MqDataType, MqDataMode>;
+
+// Constants
+
+static constexpr int32_t a2dp_sample_rates[] = {0, 44100, 48000, 88200, 96000};
+static constexpr int8_t a2dp_bits_per_samples[] = {0, 16, 24, 32};
+static constexpr ChannelMode a2dp_channel_modes[] = {
+    ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
+static constexpr CodecType a2dp_codec_types[] = {
+    CodecType::UNKNOWN, CodecType::SBC,          CodecType::AAC,
+    CodecType::APTX,    CodecType::APTX_HD,      CodecType::LDAC,
+    CodecType::LC3,     CodecType::APTX_ADAPTIVE};
+static std::vector<LatencyMode> latency_modes = {LatencyMode::FREE};
+// Helpers
+
+template <typename T>
+struct identity {
+  typedef T type;
+};
+
+template <class T>
+bool contained_in_vector(const std::vector<T>& vector,
+                         const typename identity<T>::type& target) {
+  return std::find(vector.begin(), vector.end(), target) != vector.end();
+}
+
+void copy_codec_specific(CodecConfiguration::CodecSpecific& dst,
+                         const CodecConfiguration::CodecSpecific& src) {
+  switch (src.getTag()) {
+    case CodecConfiguration::CodecSpecific::sbcConfig:
+      dst.set<CodecConfiguration::CodecSpecific::sbcConfig>(
+          src.get<CodecConfiguration::CodecSpecific::sbcConfig>());
+      break;
+    case CodecConfiguration::CodecSpecific::aacConfig:
+      dst.set<CodecConfiguration::CodecSpecific::aacConfig>(
+          src.get<CodecConfiguration::CodecSpecific::aacConfig>());
+      break;
+    case CodecConfiguration::CodecSpecific::ldacConfig:
+      dst.set<CodecConfiguration::CodecSpecific::ldacConfig>(
+          src.get<CodecConfiguration::CodecSpecific::ldacConfig>());
+      break;
+    case CodecConfiguration::CodecSpecific::aptxConfig:
+      dst.set<CodecConfiguration::CodecSpecific::aptxConfig>(
+          src.get<CodecConfiguration::CodecSpecific::aptxConfig>());
+      break;
+    case CodecConfiguration::CodecSpecific::lc3Config:
+      dst.set<CodecConfiguration::CodecSpecific::lc3Config>(
+          src.get<CodecConfiguration::CodecSpecific::lc3Config>());
+      break;
+    case CodecConfiguration::CodecSpecific::aptxAdaptiveConfig:
+      dst.set<CodecConfiguration::CodecSpecific::aptxAdaptiveConfig>(
+          src.get<CodecConfiguration::CodecSpecific::aptxAdaptiveConfig>());
+      break;
+    default:
+      break;
+  }
+}
+
+class BluetoothAudioPort : public BnBluetoothAudioPort {
+ public:
+  BluetoothAudioPort() {}
+
+  ndk::ScopedAStatus startStream(bool) { return ScopedAStatus::ok(); }
+
+  ndk::ScopedAStatus suspendStream() { return ScopedAStatus::ok(); }
+
+  ndk::ScopedAStatus stopStream() { return ScopedAStatus::ok(); }
+
+  ndk::ScopedAStatus getPresentationPosition(PresentationPosition*) {
+    return ScopedAStatus::ok();
+  }
+
+  ndk::ScopedAStatus updateSourceMetadata(const SourceMetadata&) {
+    return ScopedAStatus::ok();
+  }
+
+  ndk::ScopedAStatus updateSinkMetadata(const SinkMetadata&) {
+    return ScopedAStatus::ok();
+  }
+
+  ndk::ScopedAStatus setLatencyMode(const LatencyMode) {
+    return ScopedAStatus::ok();
+  }
+
+  ndk::ScopedAStatus setCodecType(const CodecType) {
+    return ScopedAStatus::ok();
+  }
+
+ protected:
+  virtual ~BluetoothAudioPort() = default;
+};
+
+class BluetoothAudioProviderFactoryAidl
+    : public testing::TestWithParam<std::string> {
+ public:
+  virtual void SetUp() override {
+    provider_factory_ = IBluetoothAudioProviderFactory::fromBinder(
+        SpAIBinder(AServiceManager_getService(GetParam().c_str())));
+    audio_provider_ = nullptr;
+    ASSERT_NE(provider_factory_, nullptr);
+  }
+
+  virtual void TearDown() override { provider_factory_ = nullptr; }
+
+  void GetProviderCapabilitiesHelper(const SessionType& session_type) {
+    temp_provider_capabilities_.clear();
+    auto aidl_retval = provider_factory_->getProviderCapabilities(
+        session_type, &temp_provider_capabilities_);
+    // AIDL calls should not be failed and callback has to be executed
+    ASSERT_TRUE(aidl_retval.isOk());
+    switch (session_type) {
+      case SessionType::UNKNOWN: {
+        ASSERT_TRUE(temp_provider_capabilities_.empty());
+      } break;
+      case SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH:
+      case SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH:
+      case SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH:
+      case SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH:
+      case SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH: {
+        // All software paths are mandatory and must have exact 1
+        // "PcmParameters"
+        ASSERT_EQ(temp_provider_capabilities_.size(), 1);
+        ASSERT_EQ(temp_provider_capabilities_[0].getTag(),
+                  AudioCapabilities::pcmCapabilities);
+      } break;
+      case SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH: {
+        std::unordered_set<CodecType> codec_types;
+        // empty capability means offload is unsupported
+        for (auto& audio_capability : temp_provider_capabilities_) {
+          ASSERT_EQ(audio_capability.getTag(),
+                    AudioCapabilities::a2dpCapabilities);
+          const auto& codec_capabilities =
+              audio_capability.get<AudioCapabilities::a2dpCapabilities>();
+          // Every codec can present once at most
+          ASSERT_EQ(codec_types.count(codec_capabilities.codecType), 0);
+          switch (codec_capabilities.codecType) {
+            case CodecType::SBC:
+              ASSERT_EQ(codec_capabilities.capabilities.getTag(),
+                        CodecCapabilities::Capabilities::sbcCapabilities);
+              break;
+            case CodecType::AAC:
+              ASSERT_EQ(codec_capabilities.capabilities.getTag(),
+                        CodecCapabilities::Capabilities::aacCapabilities);
+              break;
+            case CodecType::APTX:
+            case CodecType::APTX_HD:
+              ASSERT_EQ(codec_capabilities.capabilities.getTag(),
+                        CodecCapabilities::Capabilities::aptxCapabilities);
+              break;
+            case CodecType::LDAC:
+              ASSERT_EQ(codec_capabilities.capabilities.getTag(),
+                        CodecCapabilities::Capabilities::ldacCapabilities);
+              break;
+            case CodecType::LC3:
+              ASSERT_EQ(codec_capabilities.capabilities.getTag(),
+                        CodecCapabilities::Capabilities::lc3Capabilities);
+              break;
+            case CodecType::APTX_ADAPTIVE:
+            case CodecType::VENDOR:
+            case CodecType::UNKNOWN:
+              break;
+          }
+          codec_types.insert(codec_capabilities.codecType);
+        }
+      } break;
+      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());
+        for (auto audio_capability : temp_provider_capabilities_) {
+          ASSERT_EQ(audio_capability.getTag(),
+                    AudioCapabilities::leAudioCapabilities);
+        }
+      } break;
+    }
+  }
+
+  /***
+   * This helps to open the specified provider and check the openProvider()
+   * has corruct return values. BUT, to keep it simple, it does not consider
+   * the capability, and please do so at the SetUp of each session's test.
+   ***/
+  void OpenProviderHelper(const SessionType& session_type) {
+    auto aidl_retval =
+        provider_factory_->openProvider(session_type, &audio_provider_);
+    if (aidl_retval.isOk()) {
+      ASSERT_NE(session_type, SessionType::UNKNOWN);
+      ASSERT_NE(audio_provider_, nullptr);
+      audio_port_ = ndk::SharedRefBase::make<BluetoothAudioPort>();
+    } else {
+      // Hardware offloading is optional
+      ASSERT_TRUE(
+          session_type == SessionType::UNKNOWN ||
+          session_type ==
+              SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+          session_type ==
+              SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH ||
+          session_type ==
+              SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+          session_type ==
+              SessionType::
+                  LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+      ASSERT_EQ(audio_provider_, nullptr);
+    }
+  }
+
+  bool IsPcmConfigSupported(const PcmConfiguration& pcm_config) {
+    if (temp_provider_capabilities_.size() != 1 ||
+        temp_provider_capabilities_[0].getTag() !=
+            AudioCapabilities::pcmCapabilities) {
+      return false;
+    }
+    auto pcm_capability = temp_provider_capabilities_[0]
+                              .get<AudioCapabilities::pcmCapabilities>();
+    return (contained_in_vector(pcm_capability.channelMode,
+                                pcm_config.channelMode) &&
+            contained_in_vector(pcm_capability.sampleRateHz,
+                                pcm_config.sampleRateHz) &&
+            contained_in_vector(pcm_capability.bitsPerSample,
+                                pcm_config.bitsPerSample));
+  }
+
+  std::shared_ptr<IBluetoothAudioProviderFactory> provider_factory_;
+  std::shared_ptr<IBluetoothAudioProvider> audio_provider_;
+  std::shared_ptr<IBluetoothAudioPort> audio_port_;
+  std::vector<AudioCapabilities> temp_provider_capabilities_;
+
+  static constexpr SessionType kSessionTypes[] = {
+      SessionType::UNKNOWN,
+      SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+      SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH,
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+      SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+  };
+};
+
+/**
+ * Test whether we can get the FactoryService from HIDL
+ */
+TEST_P(BluetoothAudioProviderFactoryAidl, GetProviderFactoryService) {}
+
+/**
+ * Test whether we can open a provider for each provider returned by
+ * getProviderCapabilities() with non-empty capabalities
+ */
+TEST_P(BluetoothAudioProviderFactoryAidl,
+       OpenProviderAndCheckCapabilitiesBySession) {
+  for (auto session_type : kSessionTypes) {
+    GetProviderCapabilitiesHelper(session_type);
+    OpenProviderHelper(session_type);
+    // We must be able to open a provider if its getProviderCapabilities()
+    // returns non-empty list.
+    EXPECT_TRUE(temp_provider_capabilities_.empty() ||
+                audio_provider_ != nullptr);
+  }
+}
+
+/**
+ * openProvider A2DP_SOFTWARE_ENCODING_DATAPATH
+ */
+class BluetoothAudioProviderA2dpSoftwareAidl
+    : public BluetoothAudioProviderFactoryAidl {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProviderFactoryAidl::SetUp();
+    GetProviderCapabilitiesHelper(SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH);
+    OpenProviderHelper(SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH);
+    ASSERT_NE(audio_provider_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProviderFactoryAidl::TearDown();
+  }
+};
+
+/**
+ * Test whether we can open a provider of type
+ */
+TEST_P(BluetoothAudioProviderA2dpSoftwareAidl, OpenA2dpSoftwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH can be started and stopped with
+ * different PCM config
+ */
+TEST_P(BluetoothAudioProviderA2dpSoftwareAidl,
+       StartAndEndA2dpSoftwareSessionWithPossiblePcmConfig) {
+  for (auto sample_rate : a2dp_sample_rates) {
+    for (auto bits_per_sample : a2dp_bits_per_samples) {
+      for (auto channel_mode : a2dp_channel_modes) {
+        PcmConfiguration pcm_config{
+            .sampleRateHz = sample_rate,
+            .bitsPerSample = bits_per_sample,
+            .channelMode = channel_mode,
+        };
+        bool is_codec_config_valid = IsPcmConfigSupported(pcm_config);
+        DataMQDesc mq_desc;
+        auto aidl_retval = audio_provider_->startSession(
+            audio_port_, AudioConfiguration(pcm_config), latency_modes,
+            &mq_desc);
+        DataMQ data_mq(mq_desc);
+
+        EXPECT_EQ(aidl_retval.isOk(), is_codec_config_valid);
+        if (is_codec_config_valid) {
+          EXPECT_TRUE(data_mq.isValid());
+        }
+        EXPECT_TRUE(audio_provider_->endSession().isOk());
+      }
+    }
+  }
+}
+
+/**
+ * openProvider A2DP_HARDWARE_OFFLOAD_DATAPATH
+ */
+class BluetoothAudioProviderA2dpHardwareAidl
+    : public BluetoothAudioProviderFactoryAidl {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProviderFactoryAidl::SetUp();
+    GetProviderCapabilitiesHelper(
+        SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+    OpenProviderHelper(SessionType::A2DP_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+    ASSERT_TRUE(temp_provider_capabilities_.empty() ||
+                audio_provider_ != nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProviderFactoryAidl::TearDown();
+  }
+
+  bool IsOffloadSupported() { return (temp_provider_capabilities_.size() > 0); }
+
+  void GetA2dpOffloadCapabilityHelper(const CodecType& codec_type) {
+    temp_codec_capabilities_ = nullptr;
+    for (auto& codec_capability : temp_provider_capabilities_) {
+      auto& a2dp_capabilities =
+          codec_capability.get<AudioCapabilities::a2dpCapabilities>();
+      if (a2dp_capabilities.codecType != codec_type) {
+        continue;
+      }
+      temp_codec_capabilities_ = &a2dp_capabilities;
+    }
+  }
+
+  std::vector<CodecConfiguration::CodecSpecific>
+  GetSbcCodecSpecificSupportedList(bool supported) {
+    std::vector<CodecConfiguration::CodecSpecific> sbc_codec_specifics;
+    if (!supported) {
+      SbcConfiguration sbc_config{.sampleRateHz = 0, .bitsPerSample = 0};
+      sbc_codec_specifics.push_back(
+          CodecConfiguration::CodecSpecific(sbc_config));
+      return sbc_codec_specifics;
+    }
+    GetA2dpOffloadCapabilityHelper(CodecType::SBC);
+    if (temp_codec_capabilities_ == nullptr ||
+        temp_codec_capabilities_->codecType != CodecType::SBC) {
+      return sbc_codec_specifics;
+    }
+    // parse the capability
+    auto& sbc_capability =
+        temp_codec_capabilities_->capabilities
+            .get<CodecCapabilities::Capabilities::sbcCapabilities>();
+    if (sbc_capability.minBitpool > sbc_capability.maxBitpool) {
+      return sbc_codec_specifics;
+    }
+
+    // combine those parameters into one list of
+    // CodecConfiguration::CodecSpecific
+    for (int32_t sample_rate : sbc_capability.sampleRateHz) {
+      for (int8_t block_length : sbc_capability.blockLength) {
+        for (int8_t num_subbands : sbc_capability.numSubbands) {
+          for (int8_t bits_per_sample : sbc_capability.bitsPerSample) {
+            for (auto channel_mode : sbc_capability.channelMode) {
+              for (auto alloc_method : sbc_capability.allocMethod) {
+                SbcConfiguration sbc_data = {
+                    .sampleRateHz = sample_rate,
+                    .channelMode = channel_mode,
+                    .blockLength = block_length,
+                    .numSubbands = num_subbands,
+                    .allocMethod = alloc_method,
+                    .bitsPerSample = bits_per_sample,
+                    .minBitpool = sbc_capability.minBitpool,
+                    .maxBitpool = sbc_capability.maxBitpool};
+                sbc_codec_specifics.push_back(
+                    CodecConfiguration::CodecSpecific(sbc_data));
+              }
+            }
+          }
+        }
+      }
+    }
+    return sbc_codec_specifics;
+  }
+
+  std::vector<CodecConfiguration::CodecSpecific>
+  GetAacCodecSpecificSupportedList(bool supported) {
+    std::vector<CodecConfiguration::CodecSpecific> aac_codec_specifics;
+    if (!supported) {
+      AacConfiguration aac_config{.sampleRateHz = 0, .bitsPerSample = 0};
+      aac_codec_specifics.push_back(
+          CodecConfiguration::CodecSpecific(aac_config));
+      return aac_codec_specifics;
+    }
+    GetA2dpOffloadCapabilityHelper(CodecType::AAC);
+    if (temp_codec_capabilities_ == nullptr ||
+        temp_codec_capabilities_->codecType != CodecType::AAC) {
+      return aac_codec_specifics;
+    }
+    // parse the capability
+    auto& aac_capability =
+        temp_codec_capabilities_->capabilities
+            .get<CodecCapabilities::Capabilities::aacCapabilities>();
+
+    std::vector<bool> variable_bit_rate_enableds = {false};
+    if (aac_capability.variableBitRateSupported) {
+      variable_bit_rate_enableds.push_back(true);
+    }
+
+    // combine those parameters into one list of
+    // CodecConfiguration::CodecSpecific
+    for (auto object_type : aac_capability.objectType) {
+      for (int32_t sample_rate : aac_capability.sampleRateHz) {
+        for (auto channel_mode : aac_capability.channelMode) {
+          for (int8_t bits_per_sample : aac_capability.bitsPerSample) {
+            for (auto variable_bit_rate_enabled : variable_bit_rate_enableds) {
+              AacConfiguration aac_data{
+                  .objectType = object_type,
+                  .sampleRateHz = sample_rate,
+                  .channelMode = channel_mode,
+                  .variableBitRateEnabled = variable_bit_rate_enabled,
+                  .bitsPerSample = bits_per_sample};
+              aac_codec_specifics.push_back(
+                  CodecConfiguration::CodecSpecific(aac_data));
+            }
+          }
+        }
+      }
+    }
+    return aac_codec_specifics;
+  }
+
+  std::vector<CodecConfiguration::CodecSpecific>
+  GetLdacCodecSpecificSupportedList(bool supported) {
+    std::vector<CodecConfiguration::CodecSpecific> ldac_codec_specifics;
+    if (!supported) {
+      LdacConfiguration ldac_config{.sampleRateHz = 0, .bitsPerSample = 0};
+      ldac_codec_specifics.push_back(
+          CodecConfiguration::CodecSpecific(ldac_config));
+      return ldac_codec_specifics;
+    }
+    GetA2dpOffloadCapabilityHelper(CodecType::LDAC);
+    if (temp_codec_capabilities_ == nullptr ||
+        temp_codec_capabilities_->codecType != CodecType::LDAC) {
+      return ldac_codec_specifics;
+    }
+    // parse the capability
+    auto& ldac_capability =
+        temp_codec_capabilities_->capabilities
+            .get<CodecCapabilities::Capabilities::ldacCapabilities>();
+
+    // combine those parameters into one list of
+    // CodecConfiguration::CodecSpecific
+    for (int32_t sample_rate : ldac_capability.sampleRateHz) {
+      for (int8_t bits_per_sample : ldac_capability.bitsPerSample) {
+        for (auto channel_mode : ldac_capability.channelMode) {
+          for (auto quality_index : ldac_capability.qualityIndex) {
+            LdacConfiguration ldac_data{.sampleRateHz = sample_rate,
+                                        .channelMode = channel_mode,
+                                        .qualityIndex = quality_index,
+                                        .bitsPerSample = bits_per_sample};
+            ldac_codec_specifics.push_back(
+                CodecConfiguration::CodecSpecific(ldac_data));
+          }
+        }
+      }
+    }
+    return ldac_codec_specifics;
+  }
+
+  std::vector<CodecConfiguration::CodecSpecific>
+  GetAptxCodecSpecificSupportedList(bool is_hd, bool supported) {
+    std::vector<CodecConfiguration::CodecSpecific> aptx_codec_specifics;
+    if (!supported) {
+      AptxConfiguration aptx_config{.sampleRateHz = 0, .bitsPerSample = 0};
+      aptx_codec_specifics.push_back(
+          CodecConfiguration::CodecSpecific(aptx_config));
+      return aptx_codec_specifics;
+    }
+    GetA2dpOffloadCapabilityHelper(
+        (is_hd ? CodecType::APTX_HD : CodecType::APTX));
+    if (temp_codec_capabilities_ == nullptr) {
+      return aptx_codec_specifics;
+    }
+    if ((is_hd && temp_codec_capabilities_->codecType != CodecType::APTX_HD) ||
+        (!is_hd && temp_codec_capabilities_->codecType != CodecType::APTX)) {
+      return aptx_codec_specifics;
+    }
+
+    // parse the capability
+    auto& aptx_capability =
+        temp_codec_capabilities_->capabilities
+            .get<CodecCapabilities::Capabilities::aptxCapabilities>();
+
+    // combine those parameters into one list of
+    // CodecConfiguration::CodecSpecific
+    for (int8_t bits_per_sample : aptx_capability.bitsPerSample) {
+      for (int32_t sample_rate : aptx_capability.sampleRateHz) {
+        for (auto channel_mode : aptx_capability.channelMode) {
+          AptxConfiguration aptx_data{.sampleRateHz = sample_rate,
+                                      .channelMode = channel_mode,
+                                      .bitsPerSample = bits_per_sample};
+          aptx_codec_specifics.push_back(
+              CodecConfiguration::CodecSpecific(aptx_data));
+        }
+      }
+    }
+    return aptx_codec_specifics;
+  }
+
+  std::vector<CodecConfiguration::CodecSpecific>
+  GetLc3CodecSpecificSupportedList(bool supported) {
+    std::vector<CodecConfiguration::CodecSpecific> lc3_codec_specifics;
+    if (!supported) {
+      Lc3Configuration lc3_config{.samplingFrequencyHz = 0,
+                                  .frameDurationUs = 0};
+      lc3_codec_specifics.push_back(
+          CodecConfiguration::CodecSpecific(lc3_config));
+      return lc3_codec_specifics;
+    }
+    GetA2dpOffloadCapabilityHelper(CodecType::LC3);
+    if (temp_codec_capabilities_ == nullptr ||
+        temp_codec_capabilities_->codecType != CodecType::LC3) {
+      return lc3_codec_specifics;
+    }
+    // parse the capability
+    auto& lc3_capability =
+        temp_codec_capabilities_->capabilities
+            .get<CodecCapabilities::Capabilities::lc3Capabilities>();
+
+    // combine those parameters into one list of
+    // CodecConfiguration::CodecSpecific
+    for (int32_t samplingFrequencyHz : lc3_capability.samplingFrequencyHz) {
+      for (int32_t frameDurationUs : lc3_capability.frameDurationUs) {
+        for (auto channel_mode : lc3_capability.channelMode) {
+          Lc3Configuration lc3_data{.samplingFrequencyHz = samplingFrequencyHz,
+                                    .channelMode = channel_mode,
+                                    .frameDurationUs = frameDurationUs};
+          lc3_codec_specifics.push_back(
+              CodecConfiguration::CodecSpecific(lc3_data));
+        }
+      }
+    }
+    return lc3_codec_specifics;
+  }
+
+  // temp storage saves the specified codec capability by
+  // GetOffloadCodecCapabilityHelper()
+  CodecCapabilities* temp_codec_capabilities_;
+};
+
+/**
+ * Test whether we can open a provider of type
+ */
+TEST_P(BluetoothAudioProviderA2dpHardwareAidl, OpenA2dpHardwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
+ * SBC hardware encoding config
+ */
+TEST_P(BluetoothAudioProviderA2dpHardwareAidl,
+       StartAndEndA2dpSbcHardwareSession) {
+  if (!IsOffloadSupported()) {
+    return;
+  }
+
+  CodecConfiguration codec_config = {
+      .codecType = CodecType::SBC,
+      .encodedAudioBitrate = 328000,
+      .peerMtu = 1005,
+      .isScmstEnabled = false,
+  };
+  auto sbc_codec_specifics = GetSbcCodecSpecificSupportedList(true);
+
+  for (auto& codec_specific : sbc_codec_specifics) {
+    copy_codec_specific(codec_config.config, codec_specific);
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(codec_config), latency_modes, &mq_desc);
+
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
+ * AAC hardware encoding config
+ */
+TEST_P(BluetoothAudioProviderA2dpHardwareAidl,
+       StartAndEndA2dpAacHardwareSession) {
+  if (!IsOffloadSupported()) {
+    return;
+  }
+
+  CodecConfiguration codec_config = {
+      .codecType = CodecType::AAC,
+      .encodedAudioBitrate = 320000,
+      .peerMtu = 1005,
+      .isScmstEnabled = false,
+  };
+  auto aac_codec_specifics = GetAacCodecSpecificSupportedList(true);
+
+  for (auto& codec_specific : aac_codec_specifics) {
+    copy_codec_specific(codec_config.config, codec_specific);
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(codec_config), latency_modes, &mq_desc);
+
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
+ * LDAC hardware encoding config
+ */
+TEST_P(BluetoothAudioProviderA2dpHardwareAidl,
+       StartAndEndA2dpLdacHardwareSession) {
+  if (!IsOffloadSupported()) {
+    return;
+  }
+
+  CodecConfiguration codec_config = {
+      .codecType = CodecType::LDAC,
+      .encodedAudioBitrate = 990000,
+      .peerMtu = 1005,
+      .isScmstEnabled = false,
+  };
+  auto ldac_codec_specifics = GetLdacCodecSpecificSupportedList(true);
+
+  for (auto& codec_specific : ldac_codec_specifics) {
+    copy_codec_specific(codec_config.config, codec_specific);
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(codec_config), latency_modes, &mq_desc);
+
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
+ * LDAC hardware encoding config
+ */
+TEST_P(BluetoothAudioProviderA2dpHardwareAidl,
+       StartAndEndA2dpLc3HardwareSession) {
+  if (!IsOffloadSupported()) {
+    return;
+  }
+
+  CodecConfiguration codec_config = {
+      .codecType = CodecType::LC3,
+      .encodedAudioBitrate = 990000,
+      .peerMtu = 1005,
+      .isScmstEnabled = false,
+  };
+  auto lc3_codec_specifics = GetLc3CodecSpecificSupportedList(true);
+
+  for (auto& codec_specific : lc3_codec_specifics) {
+    copy_codec_specific(codec_config.config, codec_specific);
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(codec_config), latency_modes, &mq_desc);
+
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
+ * AptX hardware encoding config
+ */
+TEST_P(BluetoothAudioProviderA2dpHardwareAidl,
+       StartAndEndA2dpAptxHardwareSession) {
+  if (!IsOffloadSupported()) {
+    return;
+  }
+
+  for (auto codec_type : {CodecType::APTX, CodecType::APTX_HD}) {
+    CodecConfiguration codec_config = {
+        .codecType = codec_type,
+        .encodedAudioBitrate =
+            (codec_type == CodecType::APTX ? 352000 : 576000),
+        .peerMtu = 1005,
+        .isScmstEnabled = false,
+    };
+
+    auto aptx_codec_specifics = GetAptxCodecSpecificSupportedList(
+        (codec_type == CodecType::APTX_HD ? true : false), true);
+
+    for (auto& codec_specific : aptx_codec_specifics) {
+      copy_codec_specific(codec_config.config, codec_specific);
+      DataMQDesc mq_desc;
+      auto aidl_retval = audio_provider_->startSession(
+          audio_port_, AudioConfiguration(codec_config), latency_modes,
+          &mq_desc);
+
+      ASSERT_TRUE(aidl_retval.isOk());
+      EXPECT_TRUE(audio_provider_->endSession().isOk());
+    }
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
+ * an invalid codec config
+ */
+TEST_P(BluetoothAudioProviderA2dpHardwareAidl,
+       StartAndEndA2dpHardwareSessionInvalidCodecConfig) {
+  if (!IsOffloadSupported()) {
+    return;
+  }
+  ASSERT_NE(audio_provider_, nullptr);
+
+  std::vector<CodecConfiguration::CodecSpecific> codec_specifics;
+  for (auto codec_type : a2dp_codec_types) {
+    switch (codec_type) {
+      case CodecType::SBC:
+        codec_specifics = GetSbcCodecSpecificSupportedList(false);
+        break;
+      case CodecType::AAC:
+        codec_specifics = GetAacCodecSpecificSupportedList(false);
+        break;
+      case CodecType::LDAC:
+        codec_specifics = GetLdacCodecSpecificSupportedList(false);
+        break;
+      case CodecType::APTX:
+        codec_specifics = GetAptxCodecSpecificSupportedList(false, false);
+        break;
+      case CodecType::APTX_HD:
+        codec_specifics = GetAptxCodecSpecificSupportedList(true, false);
+        break;
+      case CodecType::LC3:
+        codec_specifics = GetLc3CodecSpecificSupportedList(false);
+        continue;
+      case CodecType::APTX_ADAPTIVE:
+      case CodecType::VENDOR:
+      case CodecType::UNKNOWN:
+        codec_specifics.clear();
+        break;
+    }
+    if (codec_specifics.empty()) {
+      continue;
+    }
+
+    CodecConfiguration codec_config = {
+        .codecType = codec_type,
+        .encodedAudioBitrate = 328000,
+        .peerMtu = 1005,
+        .isScmstEnabled = false,
+    };
+    for (auto codec_specific : codec_specifics) {
+      copy_codec_specific(codec_config.config, codec_specific);
+      DataMQDesc mq_desc;
+      auto aidl_retval = audio_provider_->startSession(
+          audio_port_, AudioConfiguration(codec_config), latency_modes,
+          &mq_desc);
+
+      // AIDL call should fail on invalid codec
+      ASSERT_FALSE(aidl_retval.isOk());
+      EXPECT_TRUE(audio_provider_->endSession().isOk());
+    }
+  }
+}
+
+/**
+ * openProvider HEARING_AID_SOFTWARE_ENCODING_DATAPATH
+ */
+class BluetoothAudioProviderHearingAidSoftwareAidl
+    : public BluetoothAudioProviderFactoryAidl {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProviderFactoryAidl::SetUp();
+    GetProviderCapabilitiesHelper(
+        SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH);
+    OpenProviderHelper(SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH);
+    ASSERT_NE(audio_provider_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProviderFactoryAidl::TearDown();
+  }
+
+  static constexpr int32_t hearing_aid_sample_rates_[] = {0, 16000, 24000};
+  static constexpr int8_t hearing_aid_bits_per_samples_[] = {0, 16, 24};
+  static constexpr ChannelMode hearing_aid_channel_modes_[] = {
+      ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
+};
+
+/**
+ * Test whether we can open a provider of type
+ */
+TEST_P(BluetoothAudioProviderHearingAidSoftwareAidl,
+       OpenHearingAidSoftwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH can be started and
+ * stopped with different PCM config
+ */
+TEST_P(BluetoothAudioProviderHearingAidSoftwareAidl,
+       StartAndEndHearingAidSessionWithPossiblePcmConfig) {
+  for (int32_t sample_rate : hearing_aid_sample_rates_) {
+    for (int8_t bits_per_sample : hearing_aid_bits_per_samples_) {
+      for (auto channel_mode : hearing_aid_channel_modes_) {
+        PcmConfiguration pcm_config{
+            .sampleRateHz = sample_rate,
+            .bitsPerSample = bits_per_sample,
+            .channelMode = channel_mode,
+        };
+        bool is_codec_config_valid = IsPcmConfigSupported(pcm_config);
+        DataMQDesc mq_desc;
+        auto aidl_retval = audio_provider_->startSession(
+            audio_port_, AudioConfiguration(pcm_config), latency_modes,
+            &mq_desc);
+        DataMQ data_mq(mq_desc);
+
+        EXPECT_EQ(aidl_retval.isOk(), is_codec_config_valid);
+        if (is_codec_config_valid) {
+          EXPECT_TRUE(data_mq.isValid());
+        }
+        EXPECT_TRUE(audio_provider_->endSession().isOk());
+      }
+    }
+  }
+}
+
+/**
+ * openProvider LE_AUDIO_SOFTWARE_ENCODING_DATAPATH
+ */
+class BluetoothAudioProviderLeAudioOutputSoftwareAidl
+    : public BluetoothAudioProviderFactoryAidl {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProviderFactoryAidl::SetUp();
+    GetProviderCapabilitiesHelper(
+        SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH);
+    OpenProviderHelper(SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH);
+    ASSERT_NE(audio_provider_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProviderFactoryAidl::TearDown();
+  }
+
+  static constexpr int32_t le_audio_output_sample_rates_[] = {
+      0, 8000, 16000, 24000, 32000, 44100, 48000,
+  };
+  static constexpr int8_t le_audio_output_bits_per_samples_[] = {0, 16, 24};
+  static constexpr ChannelMode le_audio_output_channel_modes_[] = {
+      ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
+  static constexpr int32_t le_audio_output_data_interval_us_[] = {
+      0 /* Invalid */, 10000 /* Valid 10ms */};
+};
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH can be started and
+ * stopped
+ */
+TEST_P(BluetoothAudioProviderLeAudioOutputSoftwareAidl,
+       OpenLeAudioOutputSoftwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH can be started and
+ * stopped with different PCM config
+ */
+TEST_P(BluetoothAudioProviderLeAudioOutputSoftwareAidl,
+       StartAndEndLeAudioOutputSessionWithPossiblePcmConfig) {
+  for (auto sample_rate : le_audio_output_sample_rates_) {
+    for (auto bits_per_sample : le_audio_output_bits_per_samples_) {
+      for (auto channel_mode : le_audio_output_channel_modes_) {
+        for (auto data_interval_us : le_audio_output_data_interval_us_) {
+          PcmConfiguration pcm_config{
+              .sampleRateHz = sample_rate,
+              .bitsPerSample = bits_per_sample,
+              .channelMode = channel_mode,
+              .dataIntervalUs = data_interval_us,
+          };
+          bool is_codec_config_valid =
+              IsPcmConfigSupported(pcm_config) && pcm_config.dataIntervalUs > 0;
+          DataMQDesc mq_desc;
+          auto aidl_retval = audio_provider_->startSession(
+              audio_port_, AudioConfiguration(pcm_config), latency_modes,
+              &mq_desc);
+          DataMQ data_mq(mq_desc);
+
+          EXPECT_EQ(aidl_retval.isOk(), is_codec_config_valid);
+          if (is_codec_config_valid) {
+            EXPECT_TRUE(data_mq.isValid());
+          }
+          EXPECT_TRUE(audio_provider_->endSession().isOk());
+        }
+      }
+    }
+  }
+}
+
+/**
+ * openProvider LE_AUDIO_SOFTWARE_DECODING_DATAPATH
+ */
+class BluetoothAudioProviderLeAudioInputSoftwareAidl
+    : public BluetoothAudioProviderFactoryAidl {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProviderFactoryAidl::SetUp();
+    GetProviderCapabilitiesHelper(
+        SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH);
+    OpenProviderHelper(SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH);
+    ASSERT_NE(audio_provider_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProviderFactoryAidl::TearDown();
+  }
+
+  static constexpr int32_t le_audio_input_sample_rates_[] = {
+      0, 8000, 16000, 24000, 32000, 44100, 48000};
+  static constexpr int8_t le_audio_input_bits_per_samples_[] = {0, 16, 24};
+  static constexpr ChannelMode le_audio_input_channel_modes_[] = {
+      ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
+  static constexpr int32_t le_audio_input_data_interval_us_[] = {
+      0 /* Invalid */, 10000 /* Valid 10ms */};
+};
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH can be started and
+ * stopped
+ */
+TEST_P(BluetoothAudioProviderLeAudioInputSoftwareAidl,
+       OpenLeAudioInputSoftwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_SOFTWARE_DECODING_DATAPATH can be started and
+ * stopped with different PCM config
+ */
+TEST_P(BluetoothAudioProviderLeAudioInputSoftwareAidl,
+       StartAndEndLeAudioInputSessionWithPossiblePcmConfig) {
+  for (auto sample_rate : le_audio_input_sample_rates_) {
+    for (auto bits_per_sample : le_audio_input_bits_per_samples_) {
+      for (auto channel_mode : le_audio_input_channel_modes_) {
+        for (auto data_interval_us : le_audio_input_data_interval_us_) {
+          PcmConfiguration pcm_config{
+              .sampleRateHz = sample_rate,
+              .bitsPerSample = bits_per_sample,
+              .channelMode = channel_mode,
+              .dataIntervalUs = data_interval_us,
+          };
+          bool is_codec_config_valid =
+              IsPcmConfigSupported(pcm_config) && pcm_config.dataIntervalUs > 0;
+          DataMQDesc mq_desc;
+          auto aidl_retval = audio_provider_->startSession(
+              audio_port_, AudioConfiguration(pcm_config), latency_modes,
+              &mq_desc);
+          DataMQ data_mq(mq_desc);
+
+          EXPECT_EQ(aidl_retval.isOk(), is_codec_config_valid);
+          if (is_codec_config_valid) {
+            EXPECT_TRUE(data_mq.isValid());
+          }
+          EXPECT_TRUE(audio_provider_->endSession().isOk());
+        }
+      }
+    }
+  }
+}
+
+/**
+ * openProvider LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH
+ */
+class BluetoothAudioProviderLeAudioOutputHardwareAidl
+    : public BluetoothAudioProviderFactoryAidl {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProviderFactoryAidl::SetUp();
+    GetProviderCapabilitiesHelper(
+        SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+    OpenProviderHelper(
+        SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+    ASSERT_TRUE(temp_provider_capabilities_.empty() ||
+                audio_provider_ != nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProviderFactoryAidl::TearDown();
+  }
+
+  bool IsOffloadOutputSupported() {
+    for (auto& capability : temp_provider_capabilities_) {
+      if (capability.getTag() != AudioCapabilities::leAudioCapabilities) {
+        continue;
+      }
+      auto& le_audio_capability =
+          capability.get<AudioCapabilities::leAudioCapabilities>();
+      if (le_audio_capability.unicastEncodeCapability.codecType !=
+          CodecType::UNKNOWN)
+        return true;
+    }
+    return false;
+  }
+
+  std::vector<Lc3Configuration> GetUnicastLc3SupportedList(bool decoding,
+                                                           bool supported) {
+    std::vector<Lc3Configuration> le_audio_codec_configs;
+    if (!supported) {
+      Lc3Configuration lc3_config{.samplingFrequencyHz = 0, .pcmBitDepth = 0};
+      le_audio_codec_configs.push_back(lc3_config);
+      return le_audio_codec_configs;
+    }
+
+    // There might be more than one LeAudioCodecCapabilitiesSetting
+    std::vector<Lc3Capabilities> lc3_capabilities;
+    for (auto& capability : temp_provider_capabilities_) {
+      if (capability.getTag() != AudioCapabilities::leAudioCapabilities) {
+        continue;
+      }
+      auto& le_audio_capability =
+          capability.get<AudioCapabilities::leAudioCapabilities>();
+      auto& unicast_capability =
+          decoding ? le_audio_capability.unicastDecodeCapability
+                   : le_audio_capability.unicastEncodeCapability;
+      if (unicast_capability.codecType != CodecType::LC3) {
+        continue;
+      }
+      auto& lc3_capability = unicast_capability.leAudioCodecCapabilities.get<
+          UnicastCapability::LeAudioCodecCapabilities::lc3Capabilities>();
+      lc3_capabilities.push_back(lc3_capability);
+    }
+
+    // Combine those parameters into one list of LeAudioCodecConfiguration
+    // This seems horrible, but usually each Lc3Capability only contains a
+    // single Lc3Configuration, which means every array has a length of 1.
+    for (auto& lc3_capability : lc3_capabilities) {
+      for (int32_t samplingFrequencyHz : lc3_capability.samplingFrequencyHz) {
+        for (int32_t frameDurationUs : lc3_capability.frameDurationUs) {
+          for (int32_t octetsPerFrame : lc3_capability.octetsPerFrame) {
+            Lc3Configuration lc3_config = {
+                .samplingFrequencyHz = samplingFrequencyHz,
+                .frameDurationUs = frameDurationUs,
+                .octetsPerFrame = octetsPerFrame,
+            };
+            le_audio_codec_configs.push_back(lc3_config);
+          }
+        }
+      }
+    }
+
+    return le_audio_codec_configs;
+  }
+
+  LeAudioCodecCapabilitiesSetting temp_le_audio_capabilities_;
+};
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
+ * stopped
+ */
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+       OpenLeAudioOutputHardwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
+ * stopped with Unicast hardware encoding config
+ */
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+       StartAndEndLeAudioOutputSessionWithPossibleUnicastConfig) {
+  if (!IsOffloadOutputSupported()) {
+    return;
+  }
+
+  auto lc3_codec_configs =
+      GetUnicastLc3SupportedList(false /* decoding */, true /* supported */);
+  LeAudioConfiguration le_audio_config = {
+      .codecType = CodecType::LC3,
+      .peerDelayUs = 0,
+  };
+
+  for (auto& lc3_config : lc3_codec_configs) {
+    le_audio_config.leAudioCodecConfig
+        .set<LeAudioCodecConfiguration::lc3Config>(lc3_config);
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(le_audio_config), latency_modes,
+        &mq_desc);
+
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
+ * stopped with Unicast hardware encoding config
+ *
+ * Disabled since offload codec checking is not ready
+ */
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+       DISABLED_StartAndEndLeAudioOutputSessionWithInvalidAudioConfiguration) {
+  if (!IsOffloadOutputSupported()) {
+    return;
+  }
+
+  auto lc3_codec_configs =
+      GetUnicastLc3SupportedList(false /* decoding */, false /* supported */);
+  LeAudioConfiguration le_audio_config = {
+      .codecType = CodecType::LC3,
+      .peerDelayUs = 0,
+  };
+
+  for (auto& lc3_config : lc3_codec_configs) {
+    le_audio_config.leAudioCodecConfig
+        .set<LeAudioCodecConfiguration::lc3Config>(lc3_config);
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(le_audio_config), latency_modes,
+        &mq_desc);
+
+    // AIDL call should fail on invalid codec
+    ASSERT_FALSE(aidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+/**
+ * openProvider LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH
+ */
+class BluetoothAudioProviderLeAudioInputHardwareAidl
+    : public BluetoothAudioProviderLeAudioOutputHardwareAidl {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProviderFactoryAidl::SetUp();
+    GetProviderCapabilitiesHelper(
+        SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
+    OpenProviderHelper(
+        SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
+    ASSERT_TRUE(temp_provider_capabilities_.empty() ||
+                audio_provider_ != nullptr);
+  }
+
+  bool IsOffloadInputSupported() {
+    for (auto& capability : temp_provider_capabilities_) {
+      if (capability.getTag() != AudioCapabilities::leAudioCapabilities) {
+        continue;
+      }
+      auto& le_audio_capability =
+          capability.get<AudioCapabilities::leAudioCapabilities>();
+      if (le_audio_capability.unicastDecodeCapability.codecType !=
+          CodecType::UNKNOWN)
+        return true;
+    }
+    return false;
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProviderFactoryAidl::TearDown();
+  }
+};
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
+ * stopped
+ */
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
+       OpenLeAudioInputHardwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
+ * stopped with Unicast hardware encoding config
+ */
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
+       StartAndEndLeAudioInputSessionWithPossibleUnicastConfig) {
+  if (!IsOffloadInputSupported()) {
+    return;
+  }
+
+  auto lc3_codec_configs =
+      GetUnicastLc3SupportedList(true /* decoding */, true /* supported */);
+  LeAudioConfiguration le_audio_config = {
+      .codecType = CodecType::LC3,
+      .peerDelayUs = 0,
+  };
+
+  for (auto& lc3_config : lc3_codec_configs) {
+    le_audio_config.leAudioCodecConfig
+        .set<LeAudioCodecConfiguration::lc3Config>(lc3_config);
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(le_audio_config), latency_modes,
+        &mq_desc);
+
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
+ * stopped with Unicast hardware encoding config
+ *
+ * Disabled since offload codec checking is not ready
+ */
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
+       DISABLED_StartAndEndLeAudioInputSessionWithInvalidAudioConfiguration) {
+  if (!IsOffloadInputSupported()) {
+    return;
+  }
+
+  auto lc3_codec_configs =
+      GetUnicastLc3SupportedList(true /* decoding */, false /* supported */);
+  LeAudioConfiguration le_audio_config = {
+      .codecType = CodecType::LC3,
+      .peerDelayUs = 0,
+  };
+
+  for (auto& lc3_config : lc3_codec_configs) {
+    le_audio_config.leAudioCodecConfig
+        .set<LeAudioCodecConfiguration::lc3Config>(lc3_config);
+
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(le_audio_config), latency_modes,
+        &mq_desc);
+
+    // AIDL call should fail on invalid codec
+    ASSERT_FALSE(aidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+/**
+ * openProvider LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH
+ */
+class BluetoothAudioProviderLeAudioBroadcastSoftwareAidl
+    : public BluetoothAudioProviderFactoryAidl {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProviderFactoryAidl::SetUp();
+    GetProviderCapabilitiesHelper(
+        SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH);
+    OpenProviderHelper(
+        SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH);
+    ASSERT_NE(audio_provider_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProviderFactoryAidl::TearDown();
+  }
+
+  static constexpr int32_t le_audio_output_sample_rates_[] = {
+      0, 8000, 16000, 24000, 32000, 44100, 48000,
+  };
+  static constexpr int8_t le_audio_output_bits_per_samples_[] = {0, 16, 24};
+  static constexpr ChannelMode le_audio_output_channel_modes_[] = {
+      ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
+  static constexpr int32_t le_audio_output_data_interval_us_[] = {
+      0 /* Invalid */, 10000 /* Valid 10ms */};
+};
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH can be started and
+ * stopped
+ */
+TEST_P(BluetoothAudioProviderLeAudioBroadcastSoftwareAidl,
+       OpenLeAudioOutputSoftwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH can be started and
+ * stopped with different PCM config
+ */
+TEST_P(BluetoothAudioProviderLeAudioBroadcastSoftwareAidl,
+       StartAndEndLeAudioOutputSessionWithPossiblePcmConfig) {
+  for (auto sample_rate : le_audio_output_sample_rates_) {
+    for (auto bits_per_sample : le_audio_output_bits_per_samples_) {
+      for (auto channel_mode : le_audio_output_channel_modes_) {
+        for (auto data_interval_us : le_audio_output_data_interval_us_) {
+          PcmConfiguration pcm_config{
+              .sampleRateHz = sample_rate,
+              .bitsPerSample = bits_per_sample,
+              .channelMode = channel_mode,
+              .dataIntervalUs = data_interval_us,
+          };
+          bool is_codec_config_valid =
+              IsPcmConfigSupported(pcm_config) && pcm_config.dataIntervalUs > 0;
+          DataMQDesc mq_desc;
+          auto aidl_retval = audio_provider_->startSession(
+              audio_port_, AudioConfiguration(pcm_config), latency_modes,
+              &mq_desc);
+          DataMQ data_mq(mq_desc);
+
+          EXPECT_EQ(aidl_retval.isOk(), is_codec_config_valid);
+          if (is_codec_config_valid) {
+            EXPECT_TRUE(data_mq.isValid());
+          }
+          EXPECT_TRUE(audio_provider_->endSession().isOk());
+        }
+      }
+    }
+  }
+}
+
+/**
+ * openProvider LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH
+ */
+class BluetoothAudioProviderLeAudioBroadcastHardwareAidl
+    : public BluetoothAudioProviderFactoryAidl {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProviderFactoryAidl::SetUp();
+    GetProviderCapabilitiesHelper(
+        SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+    OpenProviderHelper(
+        SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+    ASSERT_TRUE(temp_provider_capabilities_.empty() ||
+                audio_provider_ != nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProviderFactoryAidl::TearDown();
+  }
+
+  bool IsBroadcastOffloadSupported() {
+    for (auto& capability : temp_provider_capabilities_) {
+      if (capability.getTag() != AudioCapabilities::leAudioCapabilities) {
+        continue;
+      }
+      auto& le_audio_capability =
+          capability.get<AudioCapabilities::leAudioCapabilities>();
+      if (le_audio_capability.broadcastCapability.codecType !=
+          CodecType::UNKNOWN)
+        return true;
+    }
+    return false;
+  }
+
+  std::vector<Lc3Configuration> GetBroadcastLc3SupportedList(bool supported) {
+    std::vector<Lc3Configuration> le_audio_codec_configs;
+    if (!supported) {
+      Lc3Configuration lc3_config{.samplingFrequencyHz = 0, .pcmBitDepth = 0};
+      le_audio_codec_configs.push_back(lc3_config);
+      return le_audio_codec_configs;
+    }
+
+    // There might be more than one LeAudioCodecCapabilitiesSetting
+    std::vector<Lc3Capabilities> lc3_capabilities;
+    for (auto& capability : temp_provider_capabilities_) {
+      if (capability.getTag() != AudioCapabilities::leAudioCapabilities) {
+        continue;
+      }
+      auto& le_audio_capability =
+          capability.get<AudioCapabilities::leAudioCapabilities>();
+      auto& broadcast_capability = le_audio_capability.broadcastCapability;
+      if (broadcast_capability.codecType != CodecType::LC3) {
+        continue;
+      }
+      auto& lc3_capability = broadcast_capability.leAudioCodecCapabilities.get<
+          BroadcastCapability::LeAudioCodecCapabilities::lc3Capabilities>();
+      for (int idx = 0; idx < lc3_capability->size(); idx++)
+        lc3_capabilities.push_back(*lc3_capability->at(idx));
+    }
+
+    // Combine those parameters into one list of LeAudioCodecConfiguration
+    // This seems horrible, but usually each Lc3Capability only contains a
+    // single Lc3Configuration, which means every array has a length of 1.
+    for (auto& lc3_capability : lc3_capabilities) {
+      for (int32_t samplingFrequencyHz : lc3_capability.samplingFrequencyHz) {
+        for (int32_t frameDurationUs : lc3_capability.frameDurationUs) {
+          for (int32_t octetsPerFrame : lc3_capability.octetsPerFrame) {
+            Lc3Configuration lc3_config = {
+                .samplingFrequencyHz = samplingFrequencyHz,
+                .frameDurationUs = frameDurationUs,
+                .octetsPerFrame = octetsPerFrame,
+            };
+            le_audio_codec_configs.push_back(lc3_config);
+          }
+        }
+      }
+    }
+
+    return le_audio_codec_configs;
+  }
+
+  LeAudioCodecCapabilitiesSetting temp_le_audio_capabilities_;
+};
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be
+ * started and stopped
+ */
+TEST_P(BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
+       OpenLeAudioOutputHardwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be
+ * started and stopped with broadcast hardware encoding config
+ */
+TEST_P(BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
+       StartAndEndLeAudioBroadcastSessionWithPossibleBroadcastConfig) {
+  if (!IsBroadcastOffloadSupported()) {
+    return;
+  }
+
+  auto lc3_codec_configs = GetBroadcastLc3SupportedList(true /* supported */);
+  LeAudioBroadcastConfiguration le_audio_broadcast_config = {
+      .codecType = CodecType::LC3,
+      .streamMap = {},
+  };
+
+  for (auto& lc3_config : lc3_codec_configs) {
+    le_audio_broadcast_config.streamMap[0]
+        .leAudioCodecConfig.set<LeAudioCodecConfiguration::lc3Config>(
+            lc3_config);
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(le_audio_broadcast_config),
+        latency_modes, &mq_desc);
+
+    ASSERT_TRUE(aidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be
+ * started and stopped with Broadcast hardware encoding config
+ *
+ * Disabled since offload codec checking is not ready
+ */
+TEST_P(
+    BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
+    DISABLED_StartAndEndLeAudioBroadcastSessionWithInvalidAudioConfiguration) {
+  if (!IsBroadcastOffloadSupported()) {
+    return;
+  }
+
+  auto lc3_codec_configs = GetBroadcastLc3SupportedList(false /* supported */);
+  LeAudioBroadcastConfiguration le_audio_broadcast_config = {
+      .codecType = CodecType::LC3,
+      .streamMap = {},
+  };
+
+  for (auto& lc3_config : lc3_codec_configs) {
+    le_audio_broadcast_config.streamMap[0]
+        .leAudioCodecConfig.set<LeAudioCodecConfiguration::lc3Config>(
+            lc3_config);
+    DataMQDesc mq_desc;
+    auto aidl_retval = audio_provider_->startSession(
+        audio_port_, AudioConfiguration(le_audio_broadcast_config),
+        latency_modes, &mq_desc);
+
+    // AIDL call should fail on invalid codec
+    ASSERT_FALSE(aidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderFactoryAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAudioProviderFactoryAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderA2dpSoftwareAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAudioProviderA2dpSoftwareAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderA2dpHardwareAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAudioProviderA2dpHardwareAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderHearingAidSoftwareAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderHearingAidSoftwareAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderLeAudioOutputSoftwareAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderLeAudioOutputSoftwareAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderLeAudioInputSoftwareAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderLeAudioInputSoftwareAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderLeAudioOutputHardwareAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderLeAudioOutputHardwareAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderLeAudioInputHardwareAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderLeAudioInputHardwareAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderLeAudioBroadcastSoftwareAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderLeAudioBroadcastSoftwareAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::descriptor)),
+                         android::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderLeAudioBroadcastHardwareAidl);
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(
+                             IBluetoothAudioProviderFactory::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/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index 974357e..42f9455 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -14,10 +14,8 @@
     srcs: [
         "session/BluetoothAudioSession.cpp",
         "session/BluetoothAudioSession_2_1.cpp",
-        "session/BluetoothAudioSession_2_2.cpp",
         "session/BluetoothAudioSupportedCodecsDB.cpp",
         "session/BluetoothAudioSupportedCodecsDB_2_1.cpp",
-        "session/BluetoothAudioSupportedCodecsDB_2_2.cpp",
     ],
     export_include_dirs: ["session/"],
     header_libs: ["libhardware_headers"],
@@ -25,7 +23,6 @@
         "android.hardware.audio.common@5.0",
         "android.hardware.bluetooth.audio@2.0",
         "android.hardware.bluetooth.audio@2.1",
-        "android.hardware.bluetooth.audio@2.2",
         "libbase",
         "libcutils",
         "libfmq",
@@ -49,7 +46,6 @@
     shared_libs: [
         "android.hardware.bluetooth.audio@2.0",
         "android.hardware.bluetooth.audio@2.1",
-        "android.hardware.bluetooth.audio@2.2",
         "libbase",
         "libcutils",
         "libbinder_ndk",
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
index a6fd798..8fd1ab5 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -307,7 +307,9 @@
   if (session_type !=
           SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
       session_type !=
-          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH &&
+      session_type !=
+          SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
     return false;
   }
   return true;
@@ -451,7 +453,9 @@
   if (session_type !=
           SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
       session_type !=
-          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+          SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH &&
+      session_type !=
+          SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
     return std::vector<LeAudioCodecCapabilitiesSetting>(0);
   }
 
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index 967b6f3..cdee520 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -46,7 +46,8 @@
 
 void BluetoothAudioSession::OnSessionStarted(
     const std::shared_ptr<IBluetoothAudioPort> stack_iface,
-    const DataMQDesc* mq_desc, const AudioConfiguration& audio_config) {
+    const DataMQDesc* mq_desc, const AudioConfiguration& audio_config,
+    const std::vector<LatencyMode>& latency_modes) {
   std::lock_guard<std::recursive_mutex> guard(mutex_);
   if (stack_iface == nullptr) {
     LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
@@ -61,6 +62,7 @@
     audio_config_ = nullptr;
   } else {
     stack_iface_ = stack_iface;
+    latency_modes_ = latency_modes;
     LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
               << ", AudioConfiguration=" << audio_config.toString();
     ReportSessionStatus();
@@ -191,14 +193,14 @@
  *
  ***/
 
-bool BluetoothAudioSession::StartStream() {
+bool BluetoothAudioSession::StartStream(bool is_low_latency) {
   std::lock_guard<std::recursive_mutex> guard(mutex_);
   if (!IsSessionReady()) {
     LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
                << " has NO session";
     return false;
   }
-  auto hal_retval = stack_iface_->startStream();
+  auto hal_retval = stack_iface_->startStream(is_low_latency);
   if (!hal_retval.isOk()) {
     LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
                  << toString(session_type_) << " failed";
@@ -418,6 +420,7 @@
 
 void BluetoothAudioSession::ReportLowLatencyModeAllowedChanged(bool allowed) {
   std::lock_guard<std::recursive_mutex> guard(mutex_);
+  low_latency_allowed_ = allowed;
   if (observers_.empty()) {
     LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
                  << " has NO port state observer";
@@ -426,9 +429,11 @@
   for (auto& observer : observers_) {
     uint16_t cookie = observer.first;
     std::shared_ptr<PortStatusCallbacks> callback = observer.second;
-    LOG(INFO) << __func__ << " - allowed="
-              << allowed ? " allowed" : " disallowed";
-    callback->low_latency_mode_allowed_cb_(cookie, allowed);
+    LOG(INFO) << __func__
+              << " - allowed=" << (allowed ? " allowed" : " disallowed");
+    if (callback->low_latency_mode_allowed_cb_ != nullptr) {
+      callback->low_latency_mode_allowed_cb_(cookie, allowed);
+    }
   }
 }
 
@@ -530,7 +535,25 @@
   }
 }
 
-void BluetoothAudioSession::SetLatencyMode(LatencyMode latency_mode) {
+std::vector<LatencyMode> BluetoothAudioSession::GetSupportedLatencyModes() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has NO session";
+    return std::vector<LatencyMode>();
+  }
+  if (low_latency_allowed_) return latency_modes_;
+  std::vector<LatencyMode> modes;
+  for (LatencyMode mode : latency_modes_) {
+    if (mode == LatencyMode::LOW_LATENCY)
+      // ignore those low latency mode if Bluetooth stack doesn't allow
+      continue;
+    modes.push_back(mode);
+  }
+  return modes;
+}
+
+void BluetoothAudioSession::SetLatencyMode(const LatencyMode& latency_mode) {
   std::lock_guard<std::recursive_mutex> guard(mutex_);
   if (!IsSessionReady()) {
     LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
@@ -545,21 +568,6 @@
   }
 }
 
-void BluetoothAudioSession::SetCodecType(CodecType codec_type) {
-  std::lock_guard<std::recursive_mutex> guard(mutex_);
-  if (!IsSessionReady()) {
-    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
-               << " has NO session";
-    return;
-  }
-
-  auto hal_retval = stack_iface_->setCodecType(codec_type);
-  if (!hal_retval.isOk()) {
-    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
-                 << toString(session_type_) << " failed";
-  }
-}
-
 bool BluetoothAudioSession::IsAidlAvailable() {
   if (is_aidl_checked) return is_aidl_available;
   is_aidl_available =
@@ -599,4 +607,4 @@
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
-}  // namespace aidl
\ No newline at end of file
+}  // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
index 7725331..5bf17bd 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.h
@@ -27,6 +27,7 @@
 
 #include <mutex>
 #include <unordered_map>
+#include <vector>
 
 namespace aidl {
 namespace android {
@@ -120,7 +121,8 @@
    ***/
   void OnSessionStarted(const std::shared_ptr<IBluetoothAudioPort> stack_iface,
                         const DataMQDesc* mq_desc,
-                        const AudioConfiguration& audio_config);
+                        const AudioConfiguration& audio_config,
+                        const std::vector<LatencyMode>& latency_modes);
 
   /***
    * The report function is used to report that the Bluetooth stack has ended
@@ -175,14 +177,15 @@
    * Those control functions are for the bluetooth_audio module to start,
    * suspend, stop stream, to check position, and to update metadata.
    ***/
-  bool StartStream();
+  bool StartStream(bool low_latency);
   bool SuspendStream();
   void StopStream();
   bool GetPresentationPosition(PresentationPosition& presentation_position);
   void UpdateSourceMetadata(const struct source_metadata& source_metadata);
   void UpdateSinkMetadata(const struct sink_metadata& sink_metadata);
-  void SetLatencyMode(LatencyMode latency_mode);
-  void SetCodecType(CodecType codec_type);
+
+  std::vector<LatencyMode> GetSupportedLatencyModes();
+  void SetLatencyMode(const LatencyMode& latency_mode);
 
   // The control function writes stream to FMQ
   size_t OutWritePcmData(const void* buffer, size_t bytes);
@@ -203,6 +206,8 @@
   std::unique_ptr<DataMQ> data_mq_;
   // audio data configuration for both software and offloading
   std::unique_ptr<AudioConfiguration> audio_config_;
+  std::vector<LatencyMode> latency_modes_;
+  bool low_latency_allowed_ = true;
 
   // saving those registered bluetooth_audio's callbacks
   std::unordered_map<uint16_t, std::shared_ptr<struct PortStatusCallbacks>>
@@ -235,4 +240,4 @@
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
-}  // namespace aidl
\ No newline at end of file
+}  // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
index 451a31f..5b838b0 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionControl.h
@@ -98,11 +98,12 @@
   stop
    * stream, to check position, and to update metadata.
   ***/
-  static bool StartStream(const SessionType& session_type) {
+  static bool StartStream(const SessionType& session_type,
+                          bool low_latency = false) {
     std::shared_ptr<BluetoothAudioSession> session_ptr =
         BluetoothAudioSessionInstance::GetSessionInstance(session_type);
     if (session_ptr != nullptr) {
-      return session_ptr->StartStream();
+      return session_ptr->StartStream(low_latency);
     }
     return false;
   }
@@ -154,6 +155,25 @@
     }
   }
 
+  static std::vector<LatencyMode> GetSupportedLatencyModes(
+      const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->GetSupportedLatencyModes();
+    }
+    return std::vector<LatencyMode>();
+  }
+
+  static void SetLatencyMode(const SessionType& session_type,
+                             const LatencyMode& latency_mode) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->SetLatencyMode(latency_mode);
+    }
+  }
+
   /***
    * The control API writes stream to FMQ
    ***/
@@ -185,4 +205,4 @@
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
-}  // namespace aidl
\ No newline at end of file
+}  // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionReport.h b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionReport.h
index 03776b5..0350259 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionReport.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSessionReport.h
@@ -33,11 +33,13 @@
   static void OnSessionStarted(
       const SessionType& session_type,
       const std::shared_ptr<IBluetoothAudioPort> host_iface,
-      const DataMQDesc* data_mq, const AudioConfiguration& audio_config) {
+      const DataMQDesc* data_mq, const AudioConfiguration& audio_config,
+      const std::vector<LatencyMode>& latency_modes) {
     std::shared_ptr<BluetoothAudioSession> session_ptr =
         BluetoothAudioSessionInstance::GetSessionInstance(session_type);
     if (session_ptr != nullptr) {
-      session_ptr->OnSessionStarted(host_iface, data_mq, audio_config);
+      session_ptr->OnSessionStarted(host_iface, data_mq, audio_config,
+                                    latency_modes);
     }
   }
 
@@ -96,4 +98,4 @@
 }  // namespace bluetooth
 }  // namespace hardware
 }  // namespace android
-}  // namespace aidl
\ No newline at end of file
+}  // namespace aidl
diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
index 1ef9365..a4664f1 100644
--- a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
+++ b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware.cpp
@@ -28,7 +28,6 @@
 #include "../aidl_session/BluetoothAudioSessionControl.h"
 #include "HidlToAidlMiddleware_2_0.h"
 #include "HidlToAidlMiddleware_2_1.h"
-#include "HidlToAidlMiddleware_2_2.h"
 
 namespace aidl {
 namespace android {
@@ -82,15 +81,10 @@
 using Lc3FrameDuration_2_1 =
     ::android::hardware::bluetooth::audio::V2_1::Lc3FrameDuration;
 
-using LeAudioConfig_2_2 =
-    ::android::hardware::bluetooth::audio::V2_2::LeAudioConfiguration;
-using LeAudioMode_2_2 =
-    ::android::hardware::bluetooth::audio::V2_2::LeAudioMode;
-
 std::mutex legacy_callback_lock;
 std::unordered_map<
     SessionType,
-    std::unordered_map<uint16_t, std::shared_ptr<PortStatusCallbacks_2_2>>>
+    std::unordered_map<uint16_t, std::shared_ptr<PortStatusCallbacks_2_0>>>
     legacy_callback_table;
 
 const static std::unordered_map<SessionType_2_1, SessionType>
@@ -461,50 +455,6 @@
   return hidl_lc3_codec_config;
 }
 
-inline LeAudioConfig_2_2 to_hidl_leaudio_config_2_2(
-    const LeAudioConfiguration& unicast_config) {
-  LeAudioConfig_2_2 hidl_leaudio_config;
-  hidl_leaudio_config.mode = LeAudioMode_2_2::UNICAST;
-  ::android::hardware::bluetooth::audio::V2_2::UnicastConfig
-      hidl_unicast_config;
-  hidl_unicast_config.peerDelay =
-      static_cast<uint32_t>(unicast_config.peerDelayUs / 1000);
-
-  auto& lc3_config = unicast_config.leAudioCodecConfig
-                         .get<LeAudioCodecConfiguration::lc3Config>();
-  hidl_unicast_config.lc3Config = to_hidl_lc3_config_2_1(lc3_config);
-
-  hidl_unicast_config.streamMap.resize(unicast_config.streamMap.size());
-  for (int i = 0; i < unicast_config.streamMap.size(); i++) {
-    hidl_unicast_config.streamMap[i].audioChannelAllocation =
-        static_cast<uint32_t>(
-            unicast_config.streamMap[i].audioChannelAllocation);
-    hidl_unicast_config.streamMap[i].streamHandle =
-        static_cast<uint16_t>(unicast_config.streamMap[i].streamHandle);
-  }
-  return hidl_leaudio_config;
-}
-
-inline LeAudioConfig_2_2 to_hidl_leaudio_broadcast_config_2_2(
-    const LeAudioBroadcastConfiguration& broadcast_config) {
-  LeAudioConfig_2_2 hidl_leaudio_config;
-  hidl_leaudio_config.mode = LeAudioMode_2_2::BROADCAST;
-  ::android::hardware::bluetooth::audio::V2_2::BroadcastConfig
-      hidl_bcast_config;
-  hidl_bcast_config.streamMap.resize(broadcast_config.streamMap.size());
-  for (int i = 0; i < broadcast_config.streamMap.size(); i++) {
-    hidl_bcast_config.streamMap[i].audioChannelAllocation =
-        static_cast<uint32_t>(
-            broadcast_config.streamMap[i].audioChannelAllocation);
-    hidl_bcast_config.streamMap[i].streamHandle =
-        static_cast<uint16_t>(broadcast_config.streamMap[i].streamHandle);
-    hidl_bcast_config.streamMap[i].lc3Config = to_hidl_lc3_config_2_1(
-        broadcast_config.streamMap[i]
-            .leAudioCodecConfig.get<LeAudioCodecConfiguration::lc3Config>());
-  }
-  return hidl_leaudio_config;
-}
-
 inline AudioConfig_2_1 to_hidl_audio_config_2_1(
     const AudioConfiguration& audio_config) {
   AudioConfig_2_1 hidl_audio_config;
@@ -529,30 +479,6 @@
   return hidl_audio_config;
 }
 
-inline AudioConfig_2_2 to_hidl_audio_config_2_2(
-    const AudioConfiguration& audio_config) {
-  AudioConfig_2_2 hidl_audio_config;
-  switch (audio_config.getTag()) {
-    case AudioConfiguration::pcmConfig:
-      hidl_audio_config.pcmConfig(to_hidl_pcm_config_2_1(
-          audio_config.get<AudioConfiguration::pcmConfig>()));
-      break;
-    case AudioConfiguration::a2dpConfig:
-      hidl_audio_config.codecConfig(to_hidl_codec_config_2_0(
-          audio_config.get<AudioConfiguration::a2dpConfig>()));
-      break;
-    case AudioConfiguration::leAudioConfig:
-      hidl_audio_config.leAudioConfig(to_hidl_leaudio_config_2_2(
-          audio_config.get<AudioConfiguration::leAudioConfig>()));
-      break;
-    case AudioConfiguration::leAudioBroadcastConfig:
-      hidl_audio_config.leAudioConfig(to_hidl_leaudio_broadcast_config_2_2(
-          audio_config.get<AudioConfiguration::leAudioBroadcastConfig>()));
-      break;
-  }
-  return hidl_audio_config;
-}
-
 /***
  *
  * 2.0
@@ -568,18 +494,58 @@
 uint16_t HidlToAidlMiddleware_2_0::RegisterControlResultCback(
     const SessionType_2_0& session_type,
     const PortStatusCallbacks_2_0& cbacks) {
-  PortStatusCallbacks_2_2 callback_2_2{
-      .control_result_cb_ = cbacks.control_result_cb_,
-      .session_changed_cb_ = cbacks.session_changed_cb_,
+  LOG(INFO) << __func__ << ": " << toString(session_type);
+  auto aidl_session_type = from_session_type_2_0(session_type);
+  // Pass the exact reference to the lambda
+  auto& session_legacy_callback_table =
+      legacy_callback_table[aidl_session_type];
+  PortStatusCallbacks aidl_callbacks{};
+  if (cbacks.control_result_cb_) {
+    aidl_callbacks.control_result_cb_ =
+        [&session_legacy_callback_table](uint16_t cookie, bool start_resp,
+                                         const BluetoothAudioStatus& status) {
+          if (session_legacy_callback_table.find(cookie) ==
+              session_legacy_callback_table.end()) {
+            LOG(ERROR) << __func__ << ": Unknown callback invoked!";
+            return;
+          }
+          auto& cback = session_legacy_callback_table[cookie];
+          cback->control_result_cb_(cookie, start_resp, to_hidl_status(status));
+        };
+  }
+  if (cbacks.session_changed_cb_) {
+    aidl_callbacks.session_changed_cb_ =
+        [&session_legacy_callback_table](uint16_t cookie) {
+          if (session_legacy_callback_table.find(cookie) ==
+              session_legacy_callback_table.end()) {
+            LOG(ERROR) << __func__ << ": Unknown callback invoked!";
+            return;
+          }
+          auto& cback = session_legacy_callback_table[cookie];
+          cback->session_changed_cb_(cookie);
+        };
   };
-  return HidlToAidlMiddleware_2_2::RegisterControlResultCback(
-      static_cast<SessionType_2_1>(session_type), callback_2_2);
+  auto cookie = BluetoothAudioSessionControl::RegisterControlResultCback(
+      aidl_session_type, aidl_callbacks);
+  {
+    std::lock_guard<std::mutex> guard(legacy_callback_lock);
+    session_legacy_callback_table[cookie] =
+        std::make_shared<PortStatusCallbacks_2_0>(cbacks);
+  }
+  return cookie;
 }
 
 void HidlToAidlMiddleware_2_0::UnregisterControlResultCback(
     const SessionType_2_0& session_type, uint16_t cookie) {
-  HidlToAidlMiddleware_2_2::UnregisterControlResultCback(
-      static_cast<SessionType_2_1>(session_type), cookie);
+  LOG(INFO) << __func__ << ": " << toString(session_type);
+  auto aidl_session_type = from_session_type_2_0(session_type);
+  BluetoothAudioSessionControl::UnregisterControlResultCback(aidl_session_type,
+                                                             cookie);
+  auto& session_callback_table = legacy_callback_table[aidl_session_type];
+  if (session_callback_table.find(cookie) != session_callback_table.end()) {
+    std::lock_guard<std::mutex> guard(legacy_callback_lock);
+    session_callback_table.erase(cookie);
+  }
 }
 
 const AudioConfig_2_0 HidlToAidlMiddleware_2_0::GetAudioConfig(
@@ -659,124 +625,6 @@
       from_session_type_2_1(session_type)));
 }
 
-/***
- *
- * 2.2
- *
- ***/
-
-bool HidlToAidlMiddleware_2_2::IsSessionReady(
-    const SessionType_2_1& session_type) {
-  return BluetoothAudioSessionControl::IsSessionReady(
-      from_session_type_2_1(session_type));
-}
-
-uint16_t HidlToAidlMiddleware_2_2::RegisterControlResultCback(
-    const SessionType_2_1& session_type,
-    const PortStatusCallbacks_2_2& cbacks) {
-  LOG(INFO) << __func__ << ": " << toString(session_type);
-  auto aidl_session_type = from_session_type_2_1(session_type);
-  // Pass the exact reference to the lambda
-  auto& session_legacy_callback_table =
-      legacy_callback_table[aidl_session_type];
-  PortStatusCallbacks aidl_callbacks{};
-  if (cbacks.control_result_cb_) {
-    aidl_callbacks.control_result_cb_ =
-        [&session_legacy_callback_table](uint16_t cookie, bool start_resp,
-                                         const BluetoothAudioStatus& status) {
-          if (session_legacy_callback_table.find(cookie) ==
-              session_legacy_callback_table.end()) {
-            LOG(ERROR) << __func__ << ": Unknown callback invoked!";
-            return;
-          }
-          auto& cback = session_legacy_callback_table[cookie];
-          cback->control_result_cb_(cookie, start_resp, to_hidl_status(status));
-        };
-  }
-  if (cbacks.session_changed_cb_) {
-    aidl_callbacks.session_changed_cb_ =
-        [&session_legacy_callback_table](uint16_t cookie) {
-          if (session_legacy_callback_table.find(cookie) ==
-              session_legacy_callback_table.end()) {
-            LOG(ERROR) << __func__ << ": Unknown callback invoked!";
-            return;
-          }
-          auto& cback = session_legacy_callback_table[cookie];
-          cback->session_changed_cb_(cookie);
-        };
-  };
-  if (cbacks.audio_configuration_changed_cb_) {
-    aidl_callbacks.audio_configuration_changed_cb_ =
-        [&session_legacy_callback_table](uint16_t cookie) {
-          if (session_legacy_callback_table.find(cookie) ==
-              session_legacy_callback_table.end()) {
-            LOG(ERROR) << __func__ << ": Unknown callback invoked!";
-            return;
-          }
-          auto& cback = session_legacy_callback_table[cookie];
-          cback->audio_configuration_changed_cb_(cookie);
-        };
-  };
-  auto cookie = BluetoothAudioSessionControl::RegisterControlResultCback(
-      aidl_session_type, aidl_callbacks);
-  {
-    std::lock_guard<std::mutex> guard(legacy_callback_lock);
-    session_legacy_callback_table[cookie] =
-        std::make_shared<PortStatusCallbacks_2_2>(cbacks);
-  }
-  return cookie;
-}
-
-void HidlToAidlMiddleware_2_2::UnregisterControlResultCback(
-    const SessionType_2_1& session_type, uint16_t cookie) {
-  LOG(INFO) << __func__ << ": " << toString(session_type);
-  auto aidl_session_type = from_session_type_2_1(session_type);
-  BluetoothAudioSessionControl::UnregisterControlResultCback(aidl_session_type,
-                                                             cookie);
-  auto& session_callback_table = legacy_callback_table[aidl_session_type];
-  if (session_callback_table.find(cookie) != session_callback_table.end()) {
-    std::lock_guard<std::mutex> guard(legacy_callback_lock);
-    session_callback_table.erase(cookie);
-  }
-}
-
-const AudioConfig_2_2 HidlToAidlMiddleware_2_2::GetAudioConfig(
-    const SessionType_2_1& session_type) {
-  return to_hidl_audio_config_2_2(BluetoothAudioSessionControl::GetAudioConfig(
-      from_session_type_2_1(session_type)));
-}
-
-bool HidlToAidlMiddleware_2_2::StartStream(
-    const SessionType_2_1& session_type) {
-  return BluetoothAudioSessionControl::StartStream(
-      from_session_type_2_1(session_type));
-}
-
-bool HidlToAidlMiddleware_2_2::SuspendStream(
-    const SessionType_2_1& session_type) {
-  return BluetoothAudioSessionControl::SuspendStream(
-      from_session_type_2_1(session_type));
-}
-
-void HidlToAidlMiddleware_2_2::StopStream(const SessionType_2_1& session_type) {
-  return BluetoothAudioSessionControl::StopStream(
-      from_session_type_2_1(session_type));
-}
-
-void HidlToAidlMiddleware_2_2::UpdateTracksMetadata(
-    const SessionType_2_1& session_type,
-    const struct source_metadata* source_metadata) {
-  return BluetoothAudioSessionControl::UpdateSourceMetadata(
-      from_session_type_2_1(session_type), *source_metadata);
-}
-
-void HidlToAidlMiddleware_2_2::UpdateSinkMetadata(
-    const SessionType_2_1& session_type,
-    const struct sink_metadata* sink_metadata) {
-  return BluetoothAudioSessionControl::UpdateSinkMetadata(
-      from_session_type_2_1(session_type), *sink_metadata);
-}
-
 }  // namespace audio
 }  // namespace bluetooth
 }  // namespace hardware
diff --git a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_2.h b/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_2.h
deleted file mode 100644
index f6c3e5c..0000000
--- a/bluetooth/audio/utils/aidl_session/HidlToAidlMiddleware_2_2.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android/hardware/bluetooth/audio/2.2/types.h>
-
-#include "../session/BluetoothAudioSession.h"
-#include "../session/BluetoothAudioSession_2_2.h"
-
-namespace aidl {
-namespace android {
-namespace hardware {
-namespace bluetooth {
-namespace audio {
-
-using SessionType_2_1 =
-    ::android::hardware::bluetooth::audio::V2_1::SessionType;
-using PortStatusCallbacks_2_0 =
-    ::android::bluetooth::audio::PortStatusCallbacks;
-using PortStatusCallbacks_2_2 =
-    ::android::bluetooth::audio::PortStatusCallbacks_2_2;
-using AudioConfig_2_2 =
-    ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration;
-
-class HidlToAidlMiddleware_2_2 {
- public:
-  static bool IsSessionReady(const SessionType_2_1& session_type);
-
-  static uint16_t RegisterControlResultCback(
-      const SessionType_2_1& session_type,
-      const PortStatusCallbacks_2_2& cbacks);
-
-  static void UnregisterControlResultCback(const SessionType_2_1& session_type,
-                                           uint16_t cookie);
-
-  static const AudioConfig_2_2 GetAudioConfig(
-      const SessionType_2_1& session_type);
-
-  static bool StartStream(const SessionType_2_1& session_type);
-
-  static bool SuspendStream(const SessionType_2_1& session_type);
-
-  static void StopStream(const SessionType_2_1& session_type);
-
-  static void UpdateTracksMetadata(
-      const SessionType_2_1& session_type,
-      const struct source_metadata* source_metadata);
-
-  static void UpdateSinkMetadata(const SessionType_2_1& session_type,
-                                 const struct sink_metadata* sink_metadata);
-};
-
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace hardware
-}  // namespace android
-}  // namespace aidl
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_2.h b/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_2.h
deleted file mode 100644
index c270ef0..0000000
--- a/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_2.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "BluetoothAudioSession_2_2.h"
-
-namespace android {
-namespace bluetooth {
-namespace audio {
-
-class BluetoothAudioSessionControl_2_2 {
-  using SessionType_2_1 =
-      ::android::hardware::bluetooth::audio::V2_1::SessionType;
-  using AudioConfiguration_2_2 =
-      ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration;
-
- public:
-  // The control API helps to check if session is ready or not
-  // @return: true if the Bluetooth stack has started th specified session
-  static bool IsSessionReady(const SessionType_2_1& session_type) {
-    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
-    if (session_ptr != nullptr) {
-      return session_ptr->IsSessionReady();
-    }
-    return false;
-  }
-
-  // The control API helps the bluetooth_audio module to register
-  // PortStatusCallbacks
-  // @return: cookie - the assigned number to this bluetooth_audio output
-  static uint16_t RegisterControlResultCback(
-      const SessionType_2_1& session_type, const PortStatusCallbacks& cbacks) {
-    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
-    if (session_ptr != nullptr) {
-      PortStatusCallbacks_2_2 cb = {
-          .control_result_cb_ = cbacks.control_result_cb_,
-          .session_changed_cb_ = cbacks.session_changed_cb_,
-          .audio_configuration_changed_cb_ = nullptr};
-      return session_ptr->RegisterStatusCback(cb);
-    }
-    return kObserversCookieUndefined;
-  }
-
-  // The control API helps the bluetooth_audio module to register
-  // PortStatusCallbacks_2_2
-  // @return: cookie - the assigned number to this bluetooth_audio output
-  static uint16_t RegisterControlResultCback(
-      const SessionType_2_1& session_type,
-      const PortStatusCallbacks_2_2& cbacks) {
-    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
-    if (session_ptr != nullptr) {
-      return session_ptr->RegisterStatusCback(cbacks);
-    }
-    return kObserversCookieUndefined;
-  }
-
-  // The control API helps the bluetooth_audio module to unregister
-  // PortStatusCallbacks and PortStatusCallbacks_2_2
-  // @param: cookie - indicates which bluetooth_audio output is
-  static void UnregisterControlResultCback(const SessionType_2_1& session_type,
-                                           uint16_t cookie) {
-    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
-    if (session_ptr != nullptr) {
-      session_ptr->UnregisterStatusCback(cookie);
-    }
-  }
-
-  // The control API for the bluetooth_audio module to get current
-  // AudioConfiguration
-  static const AudioConfiguration_2_2 GetAudioConfig(
-      const SessionType_2_1& session_type) {
-    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
-    if (session_ptr != nullptr) {
-      return session_ptr->GetAudioConfig();
-    } else if (session_type ==
-               SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
-      return BluetoothAudioSession_2_2::kInvalidOffloadAudioConfiguration;
-    } else if (
-        session_type ==
-            SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
-        session_type ==
-            SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
-      return BluetoothAudioSession_2_2::kInvalidLeOffloadAudioConfiguration;
-    } else {
-      return BluetoothAudioSession_2_2::kInvalidSoftwareAudioConfiguration;
-    }
-  }
-
-  // Those control APIs for the bluetooth_audio module to start / suspend / stop
-  // stream, to check position, and to update metadata.
-  static bool StartStream(const SessionType_2_1& session_type) {
-    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
-    if (session_ptr != nullptr) {
-      return session_ptr->StartStream();
-    }
-    return false;
-  }
-
-  static bool SuspendStream(const SessionType_2_1& session_type) {
-    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
-    if (session_ptr != nullptr) {
-      return session_ptr->SuspendStream();
-    }
-    return false;
-  }
-
-  static void StopStream(const SessionType_2_1& session_type) {
-    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
-    if (session_ptr != nullptr) {
-      session_ptr->StopStream();
-    }
-  }
-
-  static bool GetPresentationPosition(const SessionType_2_1& session_type,
-                                      uint64_t* remote_delay_report_ns,
-                                      uint64_t* total_bytes_readed,
-                                      timespec* data_position) {
-    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
-    if (session_ptr != nullptr) {
-      return session_ptr->GetAudioSession()->GetPresentationPosition(
-          remote_delay_report_ns, total_bytes_readed, data_position);
-    }
-    return false;
-  }
-
-  static void UpdateTracksMetadata(
-      const SessionType_2_1& session_type,
-      const struct source_metadata* source_metadata) {
-    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
-    if (session_ptr != nullptr) {
-      session_ptr->UpdateTracksMetadata(source_metadata);
-    }
-  }
-
-  static void UpdateSinkMetadata(const SessionType_2_1& session_type,
-                                 const struct sink_metadata* sink_metadata) {
-    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
-    if (session_ptr != nullptr) {
-      session_ptr->UpdateSinkMetadata(sink_metadata);
-    }
-  }
-
-  // The control API writes stream to FMQ
-  static size_t OutWritePcmData(const SessionType_2_1& session_type,
-                                const void* buffer, size_t bytes) {
-    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
-    if (session_ptr != nullptr) {
-      return session_ptr->GetAudioSession()->OutWritePcmData(buffer, bytes);
-    }
-    return 0;
-  }
-
-  // The control API reads stream from FMQ
-  static size_t InReadPcmData(const SessionType_2_1& session_type, void* buffer,
-                              size_t bytes) {
-    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
-    if (session_ptr != nullptr) {
-      return session_ptr->GetAudioSession()->InReadPcmData(buffer, bytes);
-    }
-    return 0;
-  }
-};
-
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace android
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSessionReport_2_2.h b/bluetooth/audio/utils/session/BluetoothAudioSessionReport_2_2.h
deleted file mode 100644
index 17e140e..0000000
--- a/bluetooth/audio/utils/session/BluetoothAudioSessionReport_2_2.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "BluetoothAudioSession_2_2.h"
-
-namespace android {
-namespace bluetooth {
-namespace audio {
-
-class BluetoothAudioSessionReport_2_2 {
- public:
-  // The API reports the Bluetooth stack has started the session, and will
-  // inform registered bluetooth_audio outputs
-  static void OnSessionStarted(
-      const ::android::hardware::bluetooth::audio::V2_1::SessionType&
-          session_type,
-      const sp<IBluetoothAudioPort> host_iface,
-      const DataMQ::Descriptor* dataMQ,
-      const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
-          audio_config) {
-    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
-    if (session_ptr != nullptr) {
-      session_ptr->OnSessionStarted(host_iface, dataMQ, audio_config);
-    }
-  }
-
-  // The API reports the Bluetooth stack has ended the session, and will
-  // inform registered bluetooth_audio outputs
-  static void OnSessionEnded(
-      const ::android::hardware::bluetooth::audio::V2_1::SessionType&
-          session_type) {
-    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
-    if (session_ptr != nullptr) {
-      session_ptr->OnSessionEnded();
-    }
-  }
-  // The API reports the Bluetooth stack has replied the result of startStream
-  // or suspendStream, and will inform registered bluetooth_audio outputs
-  static void ReportControlStatus(
-      const ::android::hardware::bluetooth::audio::V2_1::SessionType&
-          session_type,
-      const bool& start_resp, const BluetoothAudioStatus& status) {
-    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
-    if (session_ptr != nullptr) {
-      session_ptr->ReportControlStatus(start_resp, status);
-    }
-  }
-  // The API reports the Bluetooth stack has replied the changed of the audio
-  // configuration, and will inform registered bluetooth_audio outputs
-  static void ReportAudioConfigChanged(
-      const ::android::hardware::bluetooth::audio::V2_1::SessionType&
-          session_type,
-      const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
-          audio_config) {
-    std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-        BluetoothAudioSessionInstance_2_2::GetSessionInstance(session_type);
-    if (session_ptr != nullptr) {
-      session_ptr->ReportAudioConfigChanged(audio_config);
-    }
-  }
-};
-
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace android
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp
deleted file mode 100644
index ceb0662..0000000
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.cpp
+++ /dev/null
@@ -1,636 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "BTAudioProviderSession_2_2"
-
-#include "BluetoothAudioSession_2_2.h"
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android/hardware/bluetooth/audio/2.2/IBluetoothAudioPort.h>
-
-#include "../aidl_session/HidlToAidlMiddleware_2_0.h"
-#include "../aidl_session/HidlToAidlMiddleware_2_2.h"
-
-namespace android {
-namespace bluetooth {
-namespace audio {
-
-using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_0;
-using ::aidl::android::hardware::bluetooth::audio::HidlToAidlMiddleware_2_2;
-using ::android::hardware::audio::common::V5_0::AudioContentType;
-using ::android::hardware::audio::common::V5_0::AudioSource;
-using ::android::hardware::audio::common::V5_0::AudioUsage;
-using ::android::hardware::audio::common::V5_0::PlaybackTrackMetadata;
-using ::android::hardware::audio::common::V5_0::RecordTrackMetadata;
-using ::android::hardware::audio::common::V5_0::SinkMetadata;
-using ::android::hardware::audio::common::V5_0::SourceMetadata;
-using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
-using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
-using ::android::hardware::bluetooth::audio::V2_2::LeAudioConfiguration;
-using ::android::hardware::bluetooth::audio::V2_2::LeAudioMode;
-using PcmParameters_2_1 =
-    ::android::hardware::bluetooth::audio::V2_1::PcmParameters;
-using SampleRate_2_1 = ::android::hardware::bluetooth::audio::V2_1::SampleRate;
-
-using SessionType_2_1 =
-    ::android::hardware::bluetooth::audio::V2_1::SessionType;
-using SessionType_2_0 =
-    ::android::hardware::bluetooth::audio::V2_0::SessionType;
-
-using AudioConfiguration_2_1 =
-    ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration;
-
-static constexpr PcmParameters_2_1 kInvalidPcmParameters = {
-    .sampleRate = SampleRate_2_1::RATE_UNKNOWN,
-    .channelMode = ChannelMode::UNKNOWN,
-    .bitsPerSample = BitsPerSample::BITS_UNKNOWN,
-    .dataIntervalUs = 0,
-};
-
-static LeAudioConfiguration kInvalidLeAudioConfig = {
-    .mode = LeAudioMode::UNKNOWN,
-    .config = {},
-};
-
-::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
-    BluetoothAudioSession_2_2::invalidSoftwareAudioConfiguration = {};
-::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
-    BluetoothAudioSession_2_2::invalidOffloadAudioConfiguration = {};
-::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
-    BluetoothAudioSession_2_2::invalidLeOffloadAudioConfiguration = {};
-
-using IBluetoothAudioPort_2_2 =
-    ::android::hardware::bluetooth::audio::V2_2::IBluetoothAudioPort;
-
-namespace {
-bool is_2_0_session_type(
-    const ::android::hardware::bluetooth::audio::V2_1::SessionType&
-        session_type) {
-  if (session_type == SessionType_2_1::A2DP_SOFTWARE_ENCODING_DATAPATH ||
-      session_type == SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH ||
-      session_type == SessionType_2_1::HEARING_AID_SOFTWARE_ENCODING_DATAPATH) {
-    return true;
-  } else {
-    return false;
-  }
-}
-}  // namespace
-
-BluetoothAudioSession_2_2::BluetoothAudioSession_2_2(
-    const ::android::hardware::bluetooth::audio::V2_1::SessionType&
-        session_type)
-    : audio_session(BluetoothAudioSessionInstance::GetSessionInstance(
-          static_cast<SessionType_2_0>(session_type))),
-      audio_session_2_1(
-          BluetoothAudioSessionInstance_2_1::GetSessionInstance(session_type)) {
-  if (is_2_0_session_type(session_type)) {
-    session_type_2_1_ = (SessionType_2_1::UNKNOWN);
-  } else {
-    session_type_2_1_ = (session_type);
-  }
-  raw_session_type_ = session_type;
-  invalidSoftwareAudioConfiguration.pcmConfig(kInvalidPcmParameters);
-  invalidOffloadAudioConfiguration.codecConfig(
-      audio_session->kInvalidCodecConfiguration);
-  invalidLeOffloadAudioConfiguration.leAudioConfig(kInvalidLeAudioConfig);
-}
-
-bool BluetoothAudioSession_2_2::IsSessionReady() {
-  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
-    return HidlToAidlMiddleware_2_2::IsSessionReady(raw_session_type_);
-  if (session_type_2_1_ !=
-          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
-      session_type_2_1_ !=
-          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
-    return audio_session->IsSessionReady();
-  }
-
-  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
-  return audio_session->stack_iface_ != nullptr;
-}
-
-std::shared_ptr<BluetoothAudioSession>
-BluetoothAudioSession_2_2::GetAudioSession() {
-  return audio_session;
-}
-std::shared_ptr<BluetoothAudioSession_2_1>
-BluetoothAudioSession_2_2::GetAudioSession_2_1() {
-  return audio_session_2_1;
-}
-
-void BluetoothAudioSession_2_2::UpdateTracksMetadata(
-    const struct source_metadata* source_metadata) {
-  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
-    return HidlToAidlMiddleware_2_2::UpdateTracksMetadata(raw_session_type_,
-                                                          source_metadata);
-  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
-  if (!IsSessionReady()) {
-    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
-               << " has NO session";
-    return;
-  }
-
-  ssize_t track_count = source_metadata->track_count;
-  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_2_1_)
-            << ", " << track_count << " track(s)";
-
-  if (session_type_2_1_ == SessionType_2_1::UNKNOWN) {
-    audio_session->UpdateTracksMetadata(source_metadata);
-    return;
-  }
-
-  struct playback_track_metadata* track = source_metadata->tracks;
-  SourceMetadata sourceMetadata;
-  PlaybackTrackMetadata* halMetadata;
-
-  sourceMetadata.tracks.resize(track_count);
-  halMetadata = sourceMetadata.tracks.data();
-  while (track_count && track) {
-    halMetadata->usage = static_cast<AudioUsage>(track->usage);
-    halMetadata->contentType =
-        static_cast<AudioContentType>(track->content_type);
-    halMetadata->gain = track->gain;
-    LOG(VERBOSE) << __func__ << " - SessionType=" << toString(session_type_2_1_)
-                 << ", usage=" << toString(halMetadata->usage)
-                 << ", content=" << toString(halMetadata->contentType)
-                 << ", gain=" << halMetadata->gain;
-    --track_count;
-    ++track;
-    ++halMetadata;
-  }
-  auto hal_retval = audio_session->stack_iface_->updateMetadata(sourceMetadata);
-  if (!hal_retval.isOk()) {
-    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
-                 << toString(session_type_2_1_) << " failed";
-  }
-}
-
-void BluetoothAudioSession_2_2::UpdateSinkMetadata(
-    const struct sink_metadata* sink_metadata) {
-  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
-    return HidlToAidlMiddleware_2_2::UpdateSinkMetadata(raw_session_type_,
-                                                        sink_metadata);
-  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
-  if (!IsSessionReady()) {
-    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
-               << " has NO session";
-    return;
-  }
-
-  ssize_t track_count = sink_metadata->track_count;
-  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_2_1_)
-            << ", " << track_count << " track(s)";
-  if (session_type_2_1_ == SessionType_2_1::A2DP_SOFTWARE_ENCODING_DATAPATH ||
-      session_type_2_1_ == SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
-    return;
-  }
-
-  struct record_track_metadata* track = sink_metadata->tracks;
-  SinkMetadata sinkMetadata;
-  RecordTrackMetadata* halMetadata;
-
-  sinkMetadata.tracks.resize(track_count);
-  halMetadata = sinkMetadata.tracks.data();
-  while (track_count && track) {
-    halMetadata->source = static_cast<AudioSource>(track->source);
-    halMetadata->gain = track->gain;
-    // halMetadata->destination leave unspecified
-    LOG(INFO) << __func__
-              << " - SessionType=" << toString(GetAudioSession()->session_type_)
-              << ", source=" << track->source
-              << ", dest_device=" << track->dest_device
-              << ", gain=" << track->gain
-              << ", dest_device_address=" << track->dest_device_address;
-    --track_count;
-    ++track;
-    ++halMetadata;
-  }
-
-  /* This is called just for 2.2 sessions, so it's safe to do this casting*/
-  IBluetoothAudioPort_2_2* stack_iface_2_2_ =
-      static_cast<IBluetoothAudioPort_2_2*>(audio_session->stack_iface_.get());
-  auto hal_retval = stack_iface_2_2_->updateSinkMetadata(sinkMetadata);
-  if (!hal_retval.isOk()) {
-    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
-                 << toString(session_type_2_1_) << " failed";
-  }
-}
-
-// The control function is for the bluetooth_audio module to get the current
-// AudioConfiguration
-const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
-BluetoothAudioSession_2_2::GetAudioConfig() {
-  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
-    return HidlToAidlMiddleware_2_2::GetAudioConfig(raw_session_type_);
-  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
-  if (IsSessionReady()) {
-    auto audio_config_discriminator = audio_config_2_2_.getDiscriminator();
-    // If session is unknown it means it should be 2.0 type
-    if (session_type_2_1_ != SessionType_2_1::UNKNOWN) {
-      if ((audio_config_discriminator ==
-               ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration::
-                   hidl_discriminator::pcmConfig &&
-           audio_config_2_2_ != kInvalidSoftwareAudioConfiguration) ||
-          (audio_config_discriminator ==
-               ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration::
-                   hidl_discriminator::leAudioConfig &&
-           audio_config_2_2_ != kInvalidLeOffloadAudioConfiguration))
-        return audio_config_2_2_;
-
-      ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration toConf;
-      const AudioConfiguration_2_1 fromConf =
-          GetAudioSession_2_1()->GetAudioConfig();
-      if (fromConf.getDiscriminator() ==
-          AudioConfiguration_2_1::hidl_discriminator::pcmConfig) {
-        toConf.pcmConfig(fromConf.pcmConfig());
-        return toConf;
-      }
-    }
-
-    ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration toConf;
-    const AudioConfiguration fromConf = GetAudioSession()->GetAudioConfig();
-    // pcmConfig only differs between 2.0 and 2.1 in AudioConfiguration
-    if (fromConf.getDiscriminator() ==
-        AudioConfiguration::hidl_discriminator::codecConfig) {
-      toConf.codecConfig(fromConf.codecConfig());
-    } else {
-      toConf.pcmConfig() = {
-          .sampleRate = static_cast<
-              ::android::hardware::bluetooth::audio::V2_1::SampleRate>(
-              fromConf.pcmConfig().sampleRate),
-          .channelMode = fromConf.pcmConfig().channelMode,
-          .bitsPerSample = fromConf.pcmConfig().bitsPerSample,
-          .dataIntervalUs = 0};
-    }
-    return toConf;
-  } else if (session_type_2_1_ ==
-                 SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
-             session_type_2_1_ ==
-                 SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
-    return kInvalidLeOffloadAudioConfiguration;
-  } else {
-    return kInvalidSoftwareAudioConfiguration;
-  }
-}
-
-// Those control functions are for the bluetooth_audio module to start, suspend,
-// stop stream, to check position, and to update metadata.
-bool BluetoothAudioSession_2_2::StartStream() {
-  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
-    return HidlToAidlMiddleware_2_2::StartStream(raw_session_type_);
-  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
-  if (!IsSessionReady()) {
-    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
-               << " has NO session";
-    return false;
-  }
-  auto hal_retval = audio_session->stack_iface_->startStream();
-  if (!hal_retval.isOk()) {
-    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
-                 << toString(session_type_2_1_) << " failed";
-    return false;
-  }
-  return true;
-}
-
-bool BluetoothAudioSession_2_2::SuspendStream() {
-  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
-    return HidlToAidlMiddleware_2_2::SuspendStream(raw_session_type_);
-  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
-  if (!IsSessionReady()) {
-    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_2_1_)
-               << " has NO session";
-    return false;
-  }
-  auto hal_retval = audio_session->stack_iface_->suspendStream();
-  if (!hal_retval.isOk()) {
-    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
-                 << toString(session_type_2_1_) << " failed";
-    return false;
-  }
-  return true;
-}
-
-void BluetoothAudioSession_2_2::StopStream() {
-  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
-    return HidlToAidlMiddleware_2_2::StopStream(raw_session_type_);
-  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
-  if (!IsSessionReady()) {
-    return;
-  }
-  auto hal_retval = audio_session->stack_iface_->stopStream();
-  if (!hal_retval.isOk()) {
-    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
-                 << toString(session_type_2_1_) << " failed";
-  }
-}
-
-bool BluetoothAudioSession_2_2::UpdateAudioConfig(
-    const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
-        audio_config) {
-  bool is_software_session =
-      (session_type_2_1_ == SessionType_2_1::A2DP_SOFTWARE_ENCODING_DATAPATH ||
-       session_type_2_1_ ==
-           SessionType_2_1::HEARING_AID_SOFTWARE_ENCODING_DATAPATH ||
-       session_type_2_1_ ==
-           SessionType_2_1::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH ||
-       session_type_2_1_ ==
-           SessionType_2_1::LE_AUDIO_SOFTWARE_DECODED_DATAPATH);
-  bool is_offload_a2dp_session =
-      (session_type_2_1_ == SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH);
-  bool is_offload_le_audio_session =
-      (session_type_2_1_ ==
-           SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
-       session_type_2_1_ ==
-           SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
-  auto audio_config_discriminator = audio_config.getDiscriminator();
-  bool is_software_audio_config =
-      (is_software_session &&
-       audio_config_discriminator ==
-           ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration::
-               hidl_discriminator::pcmConfig);
-  bool is_a2dp_offload_audio_config =
-      (is_offload_a2dp_session &&
-       audio_config_discriminator ==
-           ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration::
-               hidl_discriminator::codecConfig);
-  bool is_le_audio_offload_audio_config =
-      (is_offload_le_audio_session &&
-       audio_config_discriminator ==
-           ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration::
-               hidl_discriminator::leAudioConfig);
-  if (!is_software_audio_config && !is_a2dp_offload_audio_config &&
-      !is_le_audio_offload_audio_config) {
-    return false;
-  }
-  audio_config_2_2_ = audio_config;
-  return true;
-}
-
-// The report function is used to report that the Bluetooth stack has started
-// this session without any failure, and will invoke session_changed_cb_ to
-// notify those registered bluetooth_audio outputs
-void BluetoothAudioSession_2_2::OnSessionStarted(
-    const sp<IBluetoothAudioPort> stack_iface, const DataMQ::Descriptor* dataMQ,
-    const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
-        audio_config) {
-  if (session_type_2_1_ == SessionType_2_1::UNKNOWN) {
-    ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration config;
-    if (audio_config.getDiscriminator() ==
-        ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration::
-            hidl_discriminator::codecConfig) {
-      config.codecConfig(audio_config.codecConfig());
-    } else {
-      auto& tmpPcm = audio_config.pcmConfig();
-      config.pcmConfig(
-          ::android::hardware::bluetooth::audio::V2_0::PcmParameters{
-              .sampleRate = static_cast<SampleRate>(tmpPcm.sampleRate),
-              .channelMode = tmpPcm.channelMode,
-              .bitsPerSample = tmpPcm.bitsPerSample
-              /*dataIntervalUs is not passed to 2.0 */
-          });
-    }
-
-    audio_session->OnSessionStarted(stack_iface, dataMQ, config);
-  } else {
-    std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
-    if (stack_iface == nullptr) {
-      LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_2_1_)
-                 << ", IBluetoothAudioPort Invalid";
-    } else if (!UpdateAudioConfig(audio_config)) {
-      LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_2_1_)
-                 << ", AudioConfiguration=" << toString(audio_config)
-                 << " Invalid";
-    } else if (!audio_session->UpdateDataPath(dataMQ)) {
-      LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_2_1_)
-                 << " DataMQ Invalid";
-      audio_config_2_2_ =
-          ((session_type_2_1_ ==
-                SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
-            session_type_2_1_ ==
-                SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH)
-               ? kInvalidLeOffloadAudioConfiguration
-               : kInvalidSoftwareAudioConfiguration);
-    } else {
-      audio_session->stack_iface_ = stack_iface;
-      LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_2_1_)
-                << ", AudioConfiguration=" << toString(audio_config);
-      ReportSessionStatus();
-    };
-  }
-}
-
-// The report function is used to report that the Bluetooth stack has ended the
-// session, and will invoke session_changed_cb_ to notify registered
-// bluetooth_audio outputs
-void BluetoothAudioSession_2_2::OnSessionEnded() {
-  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
-  bool toggled = IsSessionReady();
-  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_2_1_);
-  if (session_type_2_1_ == SessionType_2_1::UNKNOWN) {
-    audio_session->OnSessionEnded();
-    return;
-  }
-
-  audio_config_2_2_ =
-      ((session_type_2_1_ ==
-            SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
-        session_type_2_1_ ==
-            SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH)
-           ? kInvalidLeOffloadAudioConfiguration
-           : kInvalidSoftwareAudioConfiguration);
-  audio_session->stack_iface_ = nullptr;
-  audio_session->UpdateDataPath(nullptr);
-  if (toggled) {
-    ReportSessionStatus();
-  }
-}
-
-// The control function helps the bluetooth_audio module to register
-// PortStatusCallbacks_2_2
-// @return: cookie - the assigned number to this bluetooth_audio output
-uint16_t BluetoothAudioSession_2_2::RegisterStatusCback(
-    const PortStatusCallbacks_2_2& cbacks) {
-  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
-    return HidlToAidlMiddleware_2_2::RegisterControlResultCback(
-        raw_session_type_, cbacks);
-  if (session_type_2_1_ !=
-          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
-      session_type_2_1_ !=
-          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
-    PortStatusCallbacks cb = {
-        .control_result_cb_ = cbacks.control_result_cb_,
-        .session_changed_cb_ = cbacks.session_changed_cb_};
-    return audio_session->RegisterStatusCback(cb);
-  }
-
-  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
-  uint16_t cookie = ObserversCookieGetInitValue(session_type_2_1_);
-  uint16_t cookie_upper_bound = ObserversCookieGetUpperBound(session_type_2_1_);
-
-  while (cookie < cookie_upper_bound) {
-    if (observers_.find(cookie) == observers_.end()) {
-      break;
-    }
-    ++cookie;
-  }
-  if (cookie >= cookie_upper_bound) {
-    LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_2_1_)
-               << " has " << observers_.size()
-               << " observers already (No Resource)";
-    return kObserversCookieUndefined;
-  }
-  std::shared_ptr<struct PortStatusCallbacks_2_2> cb =
-      std::make_shared<struct PortStatusCallbacks_2_2>();
-  *cb = cbacks;
-  observers_[cookie] = cb;
-  return cookie;
-}
-
-// The control function helps the bluetooth_audio module to unregister
-// PortStatusCallbacks_2_2
-// @param: cookie - indicates which bluetooth_audio output is
-void BluetoothAudioSession_2_2::UnregisterStatusCback(uint16_t cookie) {
-  if (HidlToAidlMiddleware_2_0::IsAidlAvailable())
-    return HidlToAidlMiddleware_2_2::UnregisterControlResultCback(
-        raw_session_type_, cookie);
-  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
-  if (session_type_2_1_ !=
-          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
-      session_type_2_1_ !=
-          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
-    audio_session->UnregisterStatusCback(cookie);
-    return;
-  }
-  if (observers_.erase(cookie) != 1) {
-    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_2_1_)
-                 << " no such provider=0x"
-                 << android::base::StringPrintf("%04x", cookie);
-  }
-}
-
-// invoking the registered session_changed_cb_
-void BluetoothAudioSession_2_2::ReportSessionStatus() {
-  // This is locked already by OnSessionStarted / OnSessionEnded
-  if (session_type_2_1_ !=
-          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
-      session_type_2_1_ !=
-          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
-    audio_session->ReportSessionStatus();
-    return;
-  }
-  if (observers_.empty()) {
-    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_2_1_)
-              << " has NO port state observer";
-    return;
-  }
-  for (auto& observer : observers_) {
-    uint16_t cookie = observer.first;
-    std::shared_ptr<struct PortStatusCallbacks_2_2> cb = observer.second;
-    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_2_1_)
-              << " notify to bluetooth_audio=0x"
-              << android::base::StringPrintf("%04x", cookie);
-    cb->session_changed_cb_(cookie);
-  }
-}
-
-// The report function is used to report that the Bluetooth stack has notified
-// the result of startStream or suspendStream, and will invoke
-// control_result_cb_ to notify registered bluetooth_audio outputs
-void BluetoothAudioSession_2_2::ReportControlStatus(
-    bool start_resp, const BluetoothAudioStatus& status) {
-  if (session_type_2_1_ !=
-          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
-      session_type_2_1_ !=
-          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
-    audio_session->ReportControlStatus(start_resp, status);
-    return;
-  }
-  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
-  if (observers_.empty()) {
-    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_2_1_)
-                 << " has NO port state observer";
-    return;
-  }
-  for (auto& observer : observers_) {
-    uint16_t cookie = observer.first;
-    std::shared_ptr<struct PortStatusCallbacks_2_2> cb = observer.second;
-    LOG(INFO) << __func__ << " - status=" << toString(status)
-              << " for SessionType=" << toString(session_type_2_1_)
-              << ", bluetooth_audio=0x"
-              << android::base::StringPrintf("%04x", cookie)
-              << (start_resp ? " started" : " suspended");
-    cb->control_result_cb_(cookie, start_resp, status);
-  }
-}
-
-// The report function is used to report that the Bluetooth stack has notified
-// the result of startStream or suspendStream, and will invoke
-// control_result_cb_ to notify registered bluetooth_audio outputs
-void BluetoothAudioSession_2_2::ReportAudioConfigChanged(
-    const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
-        audio_config) {
-  if (session_type_2_1_ !=
-          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
-      session_type_2_1_ !=
-          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
-    return;
-  }
-  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
-  audio_config_2_2_ = audio_config;
-  if (observers_.empty()) {
-    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_2_1_)
-                 << " has NO port state observer";
-    return;
-  }
-  for (auto& observer : observers_) {
-    uint16_t cookie = observer.first;
-    std::shared_ptr<struct PortStatusCallbacks_2_2> cb = observer.second;
-    LOG(INFO) << __func__ << " for SessionType=" << toString(session_type_2_1_)
-              << ", bluetooth_audio=0x"
-              << android::base::StringPrintf("%04x", cookie);
-    if (cb->audio_configuration_changed_cb_ != nullptr) {
-      cb->audio_configuration_changed_cb_(cookie);
-    }
-  }
-}
-
-std::unique_ptr<BluetoothAudioSessionInstance_2_2>
-    BluetoothAudioSessionInstance_2_2::instance_ptr =
-        std::unique_ptr<BluetoothAudioSessionInstance_2_2>(
-            new BluetoothAudioSessionInstance_2_2());
-
-// API to fetch the session of A2DP / Hearing Aid
-std::shared_ptr<BluetoothAudioSession_2_2>
-BluetoothAudioSessionInstance_2_2::GetSessionInstance(
-    const SessionType_2_1& session_type) {
-  std::lock_guard<std::mutex> guard(instance_ptr->mutex_);
-  if (!instance_ptr->sessions_map_.empty()) {
-    auto entry = instance_ptr->sessions_map_.find(session_type);
-    if (entry != instance_ptr->sessions_map_.end()) {
-      return entry->second;
-    }
-  }
-  std::shared_ptr<BluetoothAudioSession_2_2> session_ptr =
-      std::make_shared<BluetoothAudioSession_2_2>(session_type);
-  instance_ptr->sessions_map_[session_type] = session_ptr;
-  return session_ptr;
-}
-
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace android
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h b/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h
deleted file mode 100644
index e04ad80..0000000
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_2.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android/hardware/bluetooth/audio/2.2/types.h>
-
-#include <mutex>
-#include <unordered_map>
-
-#include "BluetoothAudioSession.h"
-#include "BluetoothAudioSession_2_1.h"
-
-namespace android {
-namespace bluetooth {
-namespace audio {
-
-inline uint16_t ObserversCookieGetInitValue(
-    const ::android::hardware::bluetooth::audio::V2_1::SessionType&
-        session_type) {
-  return (static_cast<uint16_t>(session_type) << 8 & 0xff00);
-}
-inline uint16_t ObserversCookieGetUpperBound(
-    const ::android::hardware::bluetooth::audio::V2_1::SessionType&
-        session_type) {
-  return (static_cast<uint16_t>(session_type) << 8 & 0xff00) +
-         kObserversCookieSize;
-}
-
-struct PortStatusCallbacks_2_2 {
-  // control_result_cb_ - when the Bluetooth stack reports results of
-  // streamStarted or streamSuspended, the BluetoothAudioProvider will invoke
-  // this callback to report to the bluetooth_audio module.
-  // @param: cookie - indicates which bluetooth_audio output should handle
-  // @param: start_resp - this report is for startStream or not
-  // @param: status - the result of startStream
-  std::function<void(uint16_t cookie, bool start_resp,
-                     const BluetoothAudioStatus& status)>
-      control_result_cb_;
-  // session_changed_cb_ - when the Bluetooth stack start / end session, the
-  // BluetoothAudioProvider will invoke this callback to notify to the
-  // bluetooth_audio module.
-  // @param: cookie - indicates which bluetooth_audio output should handle
-  std::function<void(uint16_t cookie)> session_changed_cb_;
-  // audio_configuration_changed_cb_ - when the Bluetooth stack change the audio
-  // configuration, the BluetoothAudioProvider will invoke this callback to
-  // notify to the bluetooth_audio module.
-  // @param: cookie - indicates which bluetooth_audio output should handle
-  std::function<void(uint16_t cookie)> audio_configuration_changed_cb_;
-};
-
-class BluetoothAudioSession_2_2 {
- private:
-  std::shared_ptr<BluetoothAudioSession> audio_session;
-  std::shared_ptr<BluetoothAudioSession_2_1> audio_session_2_1;
-
-  ::android::hardware::bluetooth::audio::V2_1::SessionType session_type_2_1_;
-  ::android::hardware::bluetooth::audio::V2_1::SessionType raw_session_type_;
-
-  // audio data configuration for both software and offloading
-  ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
-      audio_config_2_2_;
-
-  bool UpdateAudioConfig(
-      const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
-          audio_config);
-
-  static ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
-      invalidSoftwareAudioConfiguration;
-  static ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
-      invalidOffloadAudioConfiguration;
-  static ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
-      invalidLeOffloadAudioConfiguration;
-
-  // saving those registered bluetooth_audio's callbacks
-  std::unordered_map<uint16_t, std::shared_ptr<struct PortStatusCallbacks_2_2>>
-      observers_;
-
-  // invoking the registered session_changed_cb_
-  void ReportSessionStatus();
-
- public:
-  BluetoothAudioSession_2_2(
-      const ::android::hardware::bluetooth::audio::V2_1::SessionType&
-          session_type);
-
-  // The function helps to check if this session is ready or not
-  // @return: true if the Bluetooth stack has started the specified session
-  bool IsSessionReady();
-
-  std::shared_ptr<BluetoothAudioSession> GetAudioSession();
-  std::shared_ptr<BluetoothAudioSession_2_1> GetAudioSession_2_1();
-
-  // The report function is used to report that the Bluetooth stack has started
-  // this session without any failure, and will invoke session_changed_cb_ to
-  // notify those registered bluetooth_audio outputs
-  void OnSessionStarted(
-      const sp<IBluetoothAudioPort> stack_iface,
-      const DataMQ::Descriptor* dataMQ,
-      const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
-          audio_config);
-
-  // The report function is used to report that the Bluetooth stack has ended
-  // the session, and will invoke session_changed_cb_ to notify registered
-  // bluetooth_audio outputs
-  void OnSessionEnded();
-
-  // Those control functions are for the bluetooth_audio module to start,
-  // suspend, stop stream, to check position, and to update metadata.
-  bool StartStream();
-  bool SuspendStream();
-  void StopStream();
-
-  // The control function helps the bluetooth_audio module to register
-  // PortStatusCallbacks_2_2
-  // @return: cookie - the assigned number to this bluetooth_audio output
-  uint16_t RegisterStatusCback(const PortStatusCallbacks_2_2& cbacks);
-
-  // The control function helps the bluetooth_audio module to unregister
-  // PortStatusCallbacks_2_2
-  // @param: cookie - indicates which bluetooth_audio output is
-  void UnregisterStatusCback(uint16_t cookie);
-
-  // The report function is used to report that the Bluetooth stack has notified
-  // the result of startStream or suspendStream, and will invoke
-  // control_result_cb_ to notify registered bluetooth_audio outputs
-  void ReportControlStatus(bool start_resp, const BluetoothAudioStatus& status);
-
-  // 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
-  // outputs
-  void ReportAudioConfigChanged(
-      const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration&
-          audio_config);
-
-  // The control function is for the bluetooth_audio module to get the current
-  // AudioConfiguration
-  const ::android::hardware::bluetooth::audio::V2_2::AudioConfiguration
-  GetAudioConfig();
-
-  void UpdateTracksMetadata(const struct source_metadata* source_metadata);
-  void UpdateSinkMetadata(const struct sink_metadata* sink_metadata);
-
-  static constexpr ::android::hardware::bluetooth::audio::V2_2::
-      AudioConfiguration& kInvalidSoftwareAudioConfiguration =
-          invalidSoftwareAudioConfiguration;
-  static constexpr ::android::hardware::bluetooth::audio::V2_2::
-      AudioConfiguration& kInvalidOffloadAudioConfiguration =
-          invalidOffloadAudioConfiguration;
-  static constexpr ::android::hardware::bluetooth::audio::V2_2::
-      AudioConfiguration& kInvalidLeOffloadAudioConfiguration =
-          invalidLeOffloadAudioConfiguration;
-};
-
-class BluetoothAudioSessionInstance_2_2 {
- public:
-  // The API is to fetch the specified session of A2DP / Hearing Aid
-  static std::shared_ptr<BluetoothAudioSession_2_2> GetSessionInstance(
-      const ::android::hardware::bluetooth::audio::V2_1::SessionType&
-          session_type);
-
- private:
-  static std::unique_ptr<BluetoothAudioSessionInstance_2_2> instance_ptr;
-  std::mutex mutex_;
-  std::unordered_map<::android::hardware::bluetooth::audio::V2_1::SessionType,
-                     std::shared_ptr<BluetoothAudioSession_2_2>>
-      sessions_map_;
-};
-
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace android
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.cpp b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.cpp
deleted file mode 100644
index decff70..0000000
--- a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BTAudioProviderSessionCodecsDB_2_2"
-
-#include "BluetoothAudioSupportedCodecsDB_2_2.h"
-
-#include <android-base/logging.h>
-
-namespace android {
-namespace bluetooth {
-namespace audio {
-
-using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
-using ::android::hardware::bluetooth::audio::V2_1::CodecType;
-using ::android::hardware::bluetooth::audio::V2_1::Lc3FrameDuration;
-using ::android::hardware::bluetooth::audio::V2_1::Lc3Parameters;
-using ::android::hardware::bluetooth::audio::V2_1::SampleRate;
-using ::android::hardware::bluetooth::audio::V2_2::AudioLocation;
-using ::android::hardware::bluetooth::audio::V2_2::BroadcastCapability;
-using ::android::hardware::bluetooth::audio::V2_2::
-    LeAudioCodecCapabilitiesSetting;
-using ::android::hardware::bluetooth::audio::V2_2::UnicastCapability;
-using SessionType_2_1 =
-    ::android::hardware::bluetooth::audio::V2_1::SessionType;
-
-// Stores the list of offload supported capability
-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 Lc3Parameters kLc3Capability_16_1 = {
-    .samplingFrequency = SampleRate::RATE_16000,
-    .frameDuration = Lc3FrameDuration::DURATION_7500US,
-    .octetsPerFrame = 30};
-
-// Default Supported Codecs
-// LC3 16_2: sample rate: 16 kHz, frame duration: 10 ms, octets per frame: 40
-static const Lc3Parameters kLc3Capability_16_2 = {
-    .samplingFrequency = SampleRate::RATE_16000,
-    .frameDuration = Lc3FrameDuration::DURATION_10000US,
-    .octetsPerFrame = 40};
-
-// Default Supported Codecs
-// LC3 48_4: sample rate: 48 kHz, frame duration: 10 ms, octets per frame: 120
-static const Lc3Parameters kLc3Capability_48_4 = {
-    .samplingFrequency = SampleRate::RATE_48000,
-    .frameDuration = Lc3FrameDuration::DURATION_10000US,
-    .octetsPerFrame = 120};
-
-static const std::vector<Lc3Parameters> supportedLc3CapabilityList = {
-    kLc3Capability_48_4, kLc3Capability_16_2, kLc3Capability_16_1};
-
-static AudioLocation stereoAudio = static_cast<AudioLocation>(
-    AudioLocation::FRONT_LEFT | 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)};
-
-bool IsOffloadLeAudioConfigurationValid(
-    const ::android::hardware::bluetooth::audio::V2_1::SessionType&
-        session_type,
-    const ::android::hardware::bluetooth::audio::V2_2::LeAudioConfiguration&) {
-  if (session_type !=
-          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
-      session_type !=
-          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
-    return false;
-  }
-
-  // TODO: perform checks on le_audio_codec_config once we know supported
-  // parameters
-
-  return true;
-}
-
-UnicastCapability composeUnicastLc3Capability(AudioLocation audioLocation,
-                                              uint8_t deviceCnt,
-                                              uint8_t channelCount,
-                                              Lc3Parameters capability) {
-  return UnicastCapability{.codecType = CodecType::LC3,
-                           .supportedChannel = audioLocation,
-                           .deviceCount = deviceCnt,
-                           .channelCountPerDevice = channelCount,
-                           .capabilities = capability};
-}
-
-std::vector<LeAudioCodecCapabilitiesSetting> GetLeAudioOffloadCodecCapabilities(
-    const SessionType_2_1& session_type) {
-  if (session_type !=
-          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
-      session_type !=
-          SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
-    return std::vector<LeAudioCodecCapabilitiesSetting>(0);
-  }
-
-  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
-        kDefaultOffloadLeAudioCapabilities.push_back(
-            {.unicastEncodeCapability = lc3Capability,
-             .unicastDecodeCapability = lc3MonoDecodeCapability,
-             .broadcastCapability = kInvalidBroadcastCapability});
-      }
-    }
-  }
-
-  return kDefaultOffloadLeAudioCapabilities;
-}
-
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace android
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.h b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.h
deleted file mode 100644
index 34bba5f..0000000
--- a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_2.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android/hardware/bluetooth/audio/2.2/types.h>
-
-#include "BluetoothAudioSupportedCodecsDB.h"
-#include "BluetoothAudioSupportedCodecsDB_2_1.h"
-
-namespace android {
-namespace bluetooth {
-namespace audio {
-
-bool IsOffloadLeAudioConfigurationValid(
-    const ::android::hardware::bluetooth::audio::V2_1::SessionType&
-        session_type,
-    const ::android::hardware::bluetooth::audio::V2_2::LeAudioConfiguration&
-        le_audio_codec_config);
-
-std::vector<hardware::bluetooth::audio::V2_2::LeAudioCodecCapabilitiesSetting>
-GetLeAudioOffloadCodecCapabilities(
-    const ::android::hardware::bluetooth::audio::V2_1::SessionType&
-        session_type);
-}  // namespace audio
-}  // namespace bluetooth
-}  // namespace android
diff --git a/broadcastradio/1.1/vts/functional/Android.bp b/broadcastradio/1.1/vts/functional/Android.bp
index f0dfe96..0fb4eb0 100644
--- a/broadcastradio/1.1/vts/functional/Android.bp
+++ b/broadcastradio/1.1/vts/functional/Android.bp
@@ -26,6 +26,7 @@
 cc_test {
     name: "VtsHalBroadcastradioV1_1TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: ["VtsHalBroadcastradioV1_1TargetTest.cpp"],
     srcs: ["VtsHalBroadcastradioV1_1TargetTest.cpp"],
     static_libs: [
         "android.hardware.broadcastradio@1.0",
diff --git a/broadcastradio/2.0/default/Android.bp b/broadcastradio/2.0/default/Android.bp
index 870c944..38eeb15 100644
--- a/broadcastradio/2.0/default/Android.bp
+++ b/broadcastradio/2.0/default/Android.bp
@@ -25,6 +25,9 @@
 
 cc_binary {
     name: "android.hardware.broadcastradio@2.0-service",
+    vintf_fragments: [
+        "android.hardware.broadcastradio@2.0-service.xml",
+    ],
     init_rc: ["android.hardware.broadcastradio@2.0-service.rc"],
     vendor: true,
     relative_install_path: "hw",
@@ -41,7 +44,7 @@
         "TunerSession.cpp",
         "VirtualProgram.cpp",
         "VirtualRadio.cpp",
-        "service.cpp"
+        "service.cpp",
     ],
     static_libs: [
         "android.hardware.broadcastradio@common-utils-2x-lib",
diff --git a/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc
index dd8c9c6..d58ba53 100644
--- a/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc
+++ b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc
@@ -1,5 +1,6 @@
 service broadcastradio-hal2 /vendor/bin/hw/android.hardware.broadcastradio@2.0-service
-    interface android.hardware.broadcastradio@2.0::IBroadcastRadio default
+    interface android.hardware.broadcastradio@2.0::IBroadcastRadio amfm
+    interface android.hardware.broadcastradio@2.0::IBroadcastRadio dab
     class hal
     user audioserver
     group audio
diff --git a/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.xml b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.xml
new file mode 100644
index 0000000..97f2e4d
--- /dev/null
+++ b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.xml
@@ -0,0 +1,12 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.broadcastradio</name>
+        <transport>hwbinder</transport>
+        <version>2.0</version>
+        <interface>
+            <name>IBroadcastRadio</name>
+            <instance>amfm</instance>
+            <instance>dab</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/broadcastradio/2.0/vts/functional/Android.bp b/broadcastradio/2.0/vts/functional/Android.bp
index e26486d..cb50c5e 100644
--- a/broadcastradio/2.0/vts/functional/Android.bp
+++ b/broadcastradio/2.0/vts/functional/Android.bp
@@ -26,6 +26,7 @@
 cc_test {
     name: "VtsHalBroadcastradioV2_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: ["VtsHalBroadcastradioV2_0TargetTest.cpp"],
     srcs: ["VtsHalBroadcastradioV2_0TargetTest.cpp"],
     static_libs: [
         "android.hardware.broadcastradio@2.0",
diff --git a/camera/common/aidl/aidl_api/android.hardware.camera.common/current/android/hardware/camera/common/Status.aidl b/camera/common/aidl/aidl_api/android.hardware.camera.common/current/android/hardware/camera/common/Status.aidl
index e1ec189..8658927 100644
--- a/camera/common/aidl/aidl_api/android.hardware.camera.common/current/android/hardware/camera/common/Status.aidl
+++ b/camera/common/aidl/aidl_api/android.hardware.camera.common/current/android/hardware/camera/common/Status.aidl
@@ -38,8 +38,7 @@
   ILLEGAL_ARGUMENT = 1,
   CAMERA_IN_USE = 2,
   MAX_CAMERAS_IN_USE = 3,
-  METHOD_NOT_SUPPORTED = 4,
-  OPERATION_NOT_SUPPORTED = 5,
-  CAMERA_DISCONNECTED = 6,
-  INTERNAL_ERROR = 7,
+  OPERATION_NOT_SUPPORTED = 4,
+  CAMERA_DISCONNECTED = 5,
+  INTERNAL_ERROR = 6,
 }
diff --git a/camera/common/aidl/aidl_api/android.hardware.camera.common/current/android/hardware/camera/common/TagBoundaryId.aidl b/camera/common/aidl/aidl_api/android.hardware.camera.common/current/android/hardware/camera/common/TagBoundaryId.aidl
index 2c6b500..cd50483 100644
--- a/camera/common/aidl/aidl_api/android.hardware.camera.common/current/android/hardware/camera/common/TagBoundaryId.aidl
+++ b/camera/common/aidl/aidl_api/android.hardware.camera.common/current/android/hardware/camera/common/TagBoundaryId.aidl
@@ -35,5 +35,5 @@
 @Backing(type="long") @VintfStability
 enum TagBoundaryId {
   AOSP = 0,
-  VENDOR = -2147483648,
+  VENDOR = 2147483648,
 }
diff --git a/camera/common/aidl/android/hardware/camera/common/Status.aidl b/camera/common/aidl/android/hardware/camera/common/Status.aidl
index 1ea6ee8..4341d40 100644
--- a/camera/common/aidl/android/hardware/camera/common/Status.aidl
+++ b/camera/common/aidl/android/hardware/camera/common/Status.aidl
@@ -35,30 +35,26 @@
      * One of the arguments to the method call is invalid. For example,
      * the camera ID is unknown.
      */
-    ILLEGAL_ARGUMENT = 1,
+    ILLEGAL_ARGUMENT,
     /**
      * The specified camera device is already in use
      */
-    CAMERA_IN_USE = 2,
+    CAMERA_IN_USE,
     /**
      * The HAL cannot support more simultaneous cameras in use.
      */
-    MAX_CAMERAS_IN_USE = 3,
-    /**
-     * This HAL does not support this method.
-     */
-    METHOD_NOT_SUPPORTED = 4,
+    MAX_CAMERAS_IN_USE,
     /**
      * The specified camera device does not support this operation.
      */
-    OPERATION_NOT_SUPPORTED = 5,
+    OPERATION_NOT_SUPPORTED,
     /**
      * This camera device is no longer connected or otherwise available for use
      */
-    CAMERA_DISCONNECTED = 6,
+    CAMERA_DISCONNECTED,
     /**
      * The HAL has encountered an internal error and cannot complete the
      * request.
      */
-    INTERNAL_ERROR = 7,
+    INTERNAL_ERROR,
 }
diff --git a/camera/common/aidl/android/hardware/camera/common/TagBoundaryId.aidl b/camera/common/aidl/android/hardware/camera/common/TagBoundaryId.aidl
index f81e5b6..6c4ef3c 100644
--- a/camera/common/aidl/android/hardware/camera/common/TagBoundaryId.aidl
+++ b/camera/common/aidl/android/hardware/camera/common/TagBoundaryId.aidl
@@ -20,5 +20,5 @@
 @Backing(type="long")
 enum TagBoundaryId {
     AOSP = 0x0,
-    VENDOR = 0x80000000,
+    VENDOR = 0x80000000L,
 }
diff --git a/camera/device/3.7/ICameraInjectionSession.hal b/camera/device/3.7/ICameraInjectionSession.hal
index f5797c3..9be9b25 100644
--- a/camera/device/3.7/ICameraInjectionSession.hal
+++ b/camera/device/3.7/ICameraInjectionSession.hal
@@ -24,7 +24,10 @@
 import @3.7::ICameraDeviceSession;
 
 /**
- * Injection Camera device active session interface.
+ * Injection camera device active session interface.
+ *
+ * Note that this is implemented on a special camera injection hal, if it is a
+ * general camera hal, it is not necessary to implement this interface.
  *
  * When an external camera is injected to replace the internal camera session, the
  * injection session will be established in camera framework, and then
diff --git a/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/ICameraDevice.aidl b/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/ICameraDevice.aidl
index 80bfc3c..51c6067 100644
--- a/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/ICameraDevice.aidl
+++ b/camera/device/aidl/aidl_api/android.hardware.camera.device/current/android/hardware/camera/device/ICameraDevice.aidl
@@ -34,7 +34,6 @@
 package android.hardware.camera.device;
 @VintfStability
 interface ICameraDevice {
-  void dumpState(in ParcelFileDescriptor fd);
   android.hardware.camera.device.CameraMetadata getCameraCharacteristics();
   android.hardware.camera.device.CameraMetadata getPhysicalCameraCharacteristics(in String physicalCameraId);
   android.hardware.camera.common.CameraResourceCost getResourceCost();
diff --git a/camera/device/aidl/android/hardware/camera/device/ICameraDevice.aidl b/camera/device/aidl/android/hardware/camera/device/ICameraDevice.aidl
index f1f26d8..57705bc 100644
--- a/camera/device/aidl/android/hardware/camera/device/ICameraDevice.aidl
+++ b/camera/device/aidl/android/hardware/camera/device/ICameraDevice.aidl
@@ -22,7 +22,6 @@
 import android.hardware.camera.device.ICameraDeviceSession;
 import android.hardware.camera.device.ICameraInjectionSession;
 import android.hardware.camera.device.StreamConfiguration;
-
 import android.os.ParcelFileDescriptor;
 
 /**
@@ -35,31 +34,6 @@
 @VintfStability
 interface ICameraDevice {
     /**
-     * dumpState:
-     *
-     * Print out debugging state for the camera device. This may be called by
-     * the framework when the camera service is asked for a debug dump, which
-     * happens when using the dumpsys tool, or when capturing a bugreport.
-     *
-     * The passed-in file descriptor can be used to write debugging text using
-     * dprintf() or write().
-     *
-     * In case this camera device has been disconnected, the dump must not fail,
-     * but may simply print out 'Device disconnected' or equivalent.
-     *
-     * Performance requirements:
-     *
-     * This must be a non-blocking call. The HAL should return from this call
-     * in 1ms, must return from this call in 10ms. This call must avoid
-     * deadlocks, as it may be called at any point during camera operation.
-     * Any synchronization primitives used (such as mutex locks or semaphores)
-     * must be acquired with a timeout.
-     *
-     * @param fd The file descriptor to which the camera HAL must write any dumpState information.
-     */
-    void dumpState(in ParcelFileDescriptor fd);
-
-    /**
      * getCameraCharacteristics:
      *
      * Return the static camera information for this camera device. This
@@ -225,6 +199,8 @@
      *     INTERNAL_ERROR:
      *         The camera device cannot be opened due to an internal
      *         error.
+     *     OPERATION_NOT_SUPPORTED:
+     *         This camera device does not support opening an injection session.
      *     ILLEGAL_ARGUMENT:
      *         The callbacks handle is invalid (for example, it is null).
      *     CAMERA_IN_USE:
@@ -237,8 +213,7 @@
      *         longer available. This interface is now stale, and a new instance
      *         must be acquired if the device is reconnected. All subsequent
      *         calls on this interface must return CAMERA_DISCONNECTED.
-     * @return The interface to the newly-opened camera session,
-     *     or null if status is not OK.
+     * @return The interface to the newly-opened camera session, or null if status is not OK.
      */
     ICameraInjectionSession openInjectionSession(in ICameraDeviceCallback callback);
 
diff --git a/camera/metadata/3.8/types.hal b/camera/metadata/3.8/types.hal
index 1b1a7a2..8cc6646 100644
--- a/camera/metadata/3.8/types.hal
+++ b/camera/metadata/3.8/types.hal
@@ -87,7 +87,7 @@
      */
     ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP = android.hardware.camera.metadata@3.4::CameraMetadataTag:ANDROID_REQUEST_END_3_4,
 
-    /** android.request.recommendedTenBitDynamicRangeProfile [static, int32, java_public]
+    /** android.request.recommendedTenBitDynamicRangeProfile [static, int64, java_public]
      *
      * <p>Recommended 10-bit dynamic range profile.</p>
      */
@@ -154,7 +154,7 @@
 /** android.request.availableDynamicRangeProfilesMap enumeration values
  * @see ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
  */
-enum CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap : uint32_t {
+enum CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap : int64_t {
     ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD
                                                                  = 0x1,
     ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10  = 0x2,
@@ -194,7 +194,7 @@
 /** android.scaler.availableStreamUseCases enumeration values
  * @see ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES
  */
-enum CameraMetadataEnumAndroidScalerAvailableStreamUseCases : uint32_t {
+enum CameraMetadataEnumAndroidScalerAvailableStreamUseCases : int64_t {
     ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT           = 0x0,
     ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW           = 0x1,
     ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE     = 0x2,
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/AutomotiveLensFacing.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/AutomotiveLensFacing.aidl
new file mode 100644
index 0000000..14ad26e
--- /dev/null
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/AutomotiveLensFacing.aidl
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *//*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.camera.metadata;
+@Backing(type="int") @VintfStability
+enum AutomotiveLensFacing {
+  ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_OTHER = 0,
+  ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_FRONT = 1,
+  ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_REAR = 2,
+  ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_LEFT = 3,
+  ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_RIGHT = 4,
+  ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_OTHER = 5,
+  ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_LEFT = 6,
+  ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_CENTER = 7,
+  ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_RIGHT = 8,
+  ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_LEFT = 9,
+  ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_CENTER = 10,
+  ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_RIGHT = 11,
+  ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_LEFT = 12,
+  ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_CENTER = 13,
+  ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_RIGHT = 14,
+}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/BufferType.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/AutomotiveLocation.aidl
similarity index 67%
copy from drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/BufferType.aidl
copy to camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/AutomotiveLocation.aidl
index b6ec34d..5417bdb 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/BufferType.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/AutomotiveLocation.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -12,6 +12,10 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *//*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
  */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
@@ -31,9 +35,18 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.drm;
+package android.hardware.camera.metadata;
 @Backing(type="int") @VintfStability
-enum BufferType {
-  SHARED_MEMORY = 0,
-  NATIVE_HANDLE = 1,
+enum AutomotiveLocation {
+  ANDROID_AUTOMOTIVE_LOCATION_INTERIOR = 0,
+  ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_OTHER = 1,
+  ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_FRONT = 2,
+  ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_REAR = 3,
+  ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_LEFT = 4,
+  ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_RIGHT = 5,
+  ANDROID_AUTOMOTIVE_LOCATION_EXTRA_OTHER = 6,
+  ANDROID_AUTOMOTIVE_LOCATION_EXTRA_FRONT = 7,
+  ANDROID_AUTOMOTIVE_LOCATION_EXTRA_REAR = 8,
+  ANDROID_AUTOMOTIVE_LOCATION_EXTRA_LEFT = 9,
+  ANDROID_AUTOMOTIVE_LOCATION_EXTRA_RIGHT = 10,
 }
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSection.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSection.aidl
index dc33836..8bed156 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSection.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSection.aidl
@@ -68,5 +68,7 @@
   ANDROID_DISTORTION_CORRECTION = 27,
   ANDROID_HEIC = 28,
   ANDROID_HEIC_INFO = 29,
+  ANDROID_AUTOMOTIVE = 30,
+  ANDROID_AUTOMOTIVE_LENS = 31,
   VENDOR_SECTION = 32768,
 }
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
index 0c355c8..1725347 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
@@ -64,10 +64,11 @@
   ANDROID_SYNC_START = 1507328,
   ANDROID_REPROCESS_START = 1572864,
   ANDROID_DEPTH_START = 1638400,
-  VENDOR_SECTION_START = -2147483648,
   ANDROID_LOGICAL_MULTI_CAMERA_START = 1703936,
   ANDROID_DISTORTION_CORRECTION_START = 1769472,
   ANDROID_HEIC_START = 1835008,
   ANDROID_HEIC_INFO_START = 1900544,
+  ANDROID_AUTOMOTIVE_START = 1966080,
+  ANDROID_AUTOMOTIVE_LENS_START = 2031616,
   VENDOR_SECTION_START = -2147483648,
 }
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
index 432c9fd..9bb55d2 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -188,14 +188,15 @@
   ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS = 851982,
   ANDROID_SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP = 851983,
   ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES = 851984,
-  ANDROID_SCALER_DEFAULT_SECURE_IMAGE_SIZE = 851985,
-  ANDROID_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS = 851986,
-  ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION = 851987,
-  ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION = 851988,
-  ANDROID_SCALER_AVAILABLE_STALL_DURATIONS_MAXIMUM_RESOLUTION = 851989,
-  ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP_MAXIMUM_RESOLUTION = 851990,
-  ANDROID_SCALER_MULTI_RESOLUTION_STREAM_SUPPORTED = 851991,
-  ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES = 851992,
+  ANDROID_SCALER_ROTATE_AND_CROP = 851985,
+  ANDROID_SCALER_DEFAULT_SECURE_IMAGE_SIZE = 851986,
+  ANDROID_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS = 851987,
+  ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION = 851988,
+  ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION = 851989,
+  ANDROID_SCALER_AVAILABLE_STALL_DURATIONS_MAXIMUM_RESOLUTION = 851990,
+  ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP_MAXIMUM_RESOLUTION = 851991,
+  ANDROID_SCALER_MULTI_RESOLUTION_STREAM_SUPPORTED = 851992,
+  ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES = 851994,
   ANDROID_SENSOR_EXPOSURE_TIME = 917504,
   ANDROID_SENSOR_FRAME_DURATION = 917505,
   ANDROID_SENSOR_SENSITIVITY = 917506,
@@ -325,4 +326,6 @@
   ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS_MAXIMUM_RESOLUTION = 1835013,
   ANDROID_HEIC_INFO_SUPPORTED = 1900544,
   ANDROID_HEIC_INFO_MAX_JPEG_APP_SEGMENTS_COUNT = 1900545,
+  ANDROID_AUTOMOTIVE_LOCATION = 1966080,
+  ANDROID_AUTOMOTIVE_LENS_FACING = 2031616,
 }
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/LensPoseReference.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/LensPoseReference.aidl
index 275d77b..b2d837a 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/LensPoseReference.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/LensPoseReference.aidl
@@ -41,4 +41,5 @@
   ANDROID_LENS_POSE_REFERENCE_PRIMARY_CAMERA = 0,
   ANDROID_LENS_POSE_REFERENCE_GYROSCOPE = 1,
   ANDROID_LENS_POSE_REFERENCE_UNDEFINED = 2,
+  ANDROID_LENS_POSE_REFERENCE_AUTOMOTIVE = 3,
 }
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/RequestAvailableCapabilities.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/RequestAvailableCapabilities.aidl
index 4462936..8dc2aa2 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/RequestAvailableCapabilities.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/RequestAvailableCapabilities.aidl
@@ -57,4 +57,5 @@
   ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR = 16,
   ANDROID_REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING = 17,
   ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT = 18,
+  ANDROID_REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE = 19,
 }
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/RequestAvailableDynamicRangeProfilesMap.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/RequestAvailableDynamicRangeProfilesMap.aidl
index cec4ac1..16e38ba 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/RequestAvailableDynamicRangeProfilesMap.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/RequestAvailableDynamicRangeProfilesMap.aidl
@@ -36,7 +36,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.camera.metadata;
-@Backing(type="int") @VintfStability
+@Backing(type="long") @VintfStability
 enum RequestAvailableDynamicRangeProfilesMap {
   ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD = 1,
   ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10 = 2,
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
index 0ed55a3..bfa4f1a 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
@@ -36,7 +36,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.camera.metadata;
-@Backing(type="int") @VintfStability
+@Backing(type="long") @VintfStability
 enum ScalerAvailableStreamUseCases {
   ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT = 0,
   ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW = 1,
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/SensorTestPatternMode.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/SensorTestPatternMode.aidl
index d013bf4..3f49b9a 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/SensorTestPatternMode.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/SensorTestPatternMode.aidl
@@ -43,6 +43,6 @@
   ANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS = 2,
   ANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY = 3,
   ANDROID_SENSOR_TEST_PATTERN_MODE_PN9 = 4,
+  ANDROID_SENSOR_TEST_PATTERN_MODE_BLACK = 5,
   ANDROID_SENSOR_TEST_PATTERN_MODE_CUSTOM1 = 256,
-  ANDROID_SENSOR_TEST_PATTERN_MODE_BLACK = 257,
 }
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/AutomotiveLensFacing.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/AutomotiveLensFacing.aidl
new file mode 100644
index 0000000..8cd2229
--- /dev/null
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/AutomotiveLensFacing.aidl
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata;
+
+/**
+ * android.automotive.lens.facing enumeration values
+ * @see ANDROID_AUTOMOTIVE_LENS_FACING
+ */
+@VintfStability
+@Backing(type="int")
+enum AutomotiveLensFacing {
+    ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_OTHER,
+    ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_FRONT,
+    ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_REAR,
+    ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_LEFT,
+    ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_RIGHT,
+    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_OTHER,
+    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_LEFT,
+    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_CENTER,
+    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_RIGHT,
+    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_LEFT,
+    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_CENTER,
+    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_RIGHT,
+    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_LEFT,
+    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_CENTER,
+    ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_RIGHT,
+}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/AutomotiveLocation.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/AutomotiveLocation.aidl
new file mode 100644
index 0000000..0ef64b4
--- /dev/null
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/AutomotiveLocation.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata;
+
+/**
+ * android.automotive.location enumeration values
+ * @see ANDROID_AUTOMOTIVE_LOCATION
+ */
+@VintfStability
+@Backing(type="int")
+enum AutomotiveLocation {
+    ANDROID_AUTOMOTIVE_LOCATION_INTERIOR,
+    ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_OTHER,
+    ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_FRONT,
+    ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_REAR,
+    ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_LEFT,
+    ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_RIGHT,
+    ANDROID_AUTOMOTIVE_LOCATION_EXTRA_OTHER,
+    ANDROID_AUTOMOTIVE_LOCATION_EXTRA_FRONT,
+    ANDROID_AUTOMOTIVE_LOCATION_EXTRA_REAR,
+    ANDROID_AUTOMOTIVE_LOCATION_EXTRA_LEFT,
+    ANDROID_AUTOMOTIVE_LOCATION_EXTRA_RIGHT,
+}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSection.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSection.aidl
index cc3d3b3..99e28b9 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSection.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSection.aidl
@@ -59,5 +59,7 @@
     ANDROID_DISTORTION_CORRECTION,
     ANDROID_HEIC,
     ANDROID_HEIC_INFO,
+    ANDROID_AUTOMOTIVE,
+    ANDROID_AUTOMOTIVE_LENS,
     VENDOR_SECTION = 0x8000,
 }
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
index d5cd0b4..62c71e9 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
@@ -57,10 +57,11 @@
     ANDROID_SYNC_START = CameraMetadataSection.ANDROID_SYNC << 16,
     ANDROID_REPROCESS_START = CameraMetadataSection.ANDROID_REPROCESS << 16,
     ANDROID_DEPTH_START = CameraMetadataSection.ANDROID_DEPTH << 16,
-    VENDOR_SECTION_START = CameraMetadataSection.VENDOR_SECTION << 16,
     ANDROID_LOGICAL_MULTI_CAMERA_START = CameraMetadataSection.ANDROID_LOGICAL_MULTI_CAMERA << 16,
     ANDROID_DISTORTION_CORRECTION_START = CameraMetadataSection.ANDROID_DISTORTION_CORRECTION << 16,
     ANDROID_HEIC_START = CameraMetadataSection.ANDROID_HEIC << 16,
     ANDROID_HEIC_INFO_START = CameraMetadataSection.ANDROID_HEIC_INFO << 16,
+    ANDROID_AUTOMOTIVE_START = CameraMetadataSection.ANDROID_AUTOMOTIVE << 16,
+    ANDROID_AUTOMOTIVE_LENS_START = CameraMetadataSection.ANDROID_AUTOMOTIVE_LENS << 16,
     VENDOR_SECTION_START = CameraMetadataSection.VENDOR_SECTION << 16,
 }
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
index 1f388d9..692421a 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -1024,7 +1024,7 @@
      */
     ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP,
     /**
-     * android.request.recommendedTenBitDynamicRangeProfile [static, int32, java_public]
+     * android.request.recommendedTenBitDynamicRangeProfile [static, int64, java_public]
      *
      * <p>Recommended 10-bit dynamic range profile.</p>
      */
@@ -1161,6 +1161,13 @@
      */
     ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES,
     /**
+     * android.scaler.rotateAndCrop [dynamic, enum, public]
+     *
+     * <p>Whether a rotation-and-crop operation is applied to processed
+     * outputs from the camera.</p>
+     */
+    ANDROID_SCALER_ROTATE_AND_CROP,
+    /**
      * android.scaler.defaultSecureImageSize [static, int32[], public]
      *
      * <p>Default YUV/PRIVATE size to use for requesting secure image buffers.</p>
@@ -1229,7 +1236,7 @@
      *
      * <p>The stream use cases supported by this camera device.</p>
      */
-    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES,
+    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES = 851994,
     /**
      * android.sensor.exposureTime [dynamic, int64, public]
      *
@@ -2232,4 +2239,17 @@
      * <p>The maximum number of Jpeg APP segments supported by the camera HAL device.</p>
      */
     ANDROID_HEIC_INFO_MAX_JPEG_APP_SEGMENTS_COUNT,
+    /**
+     * android.automotive.location [static, enum, public]
+     *
+     * <p>Location of the cameras on the automotive devices.</p>
+     */
+    ANDROID_AUTOMOTIVE_LOCATION = CameraMetadataSectionStart.ANDROID_AUTOMOTIVE_START,
+    /**
+     * android.automotive.lens.facing [static, enum[], public]
+     *
+     * <p>The direction of the camera faces relative to the vehicle body frame and the
+     * passenger seats.</p>
+     */
+    ANDROID_AUTOMOTIVE_LENS_FACING = CameraMetadataSectionStart.ANDROID_AUTOMOTIVE_LENS_START,
 }
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/ColorCorrectionMode.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/ColorCorrectionMode.aidl
index 33a0879..080ca02 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/ColorCorrectionMode.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/ColorCorrectionMode.aidl
@@ -22,10 +22,7 @@
 
 package android.hardware.camera.metadata;
 
-/*
- * Enumeration definitions for the various entries that need them
- *
- *
+/**
  * android.colorCorrection.mode enumeration values
  * @see ANDROID_COLOR_CORRECTION_MODE
  */
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/ControlAeMode.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/ControlAeMode.aidl
index 9a9d5bc..e2f5553 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/ControlAeMode.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/ControlAeMode.aidl
@@ -22,11 +22,8 @@
 
 package android.hardware.camera.metadata;
 
-/*
- * Enumeration definitions for the various entries that need them
- *
- *
- * android.control.aeMode enumeration values added
+/**
+ * android.control.aeMode enumeration values
  * @see ANDROID_CONTROL_AE_MODE
  */
 @VintfStability
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/ControlMode.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/ControlMode.aidl
index 047556d..d9ab9ab 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/ControlMode.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/ControlMode.aidl
@@ -22,10 +22,7 @@
 
 package android.hardware.camera.metadata;
 
-/*
- * Enumeration definitions for the various entries that need them
- *
- *
+/**
  * android.control.mode enumeration values
  * @see ANDROID_CONTROL_MODE
  */
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/ControlVideoStabilizationMode.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/ControlVideoStabilizationMode.aidl
index 4046c4e..497846c 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/ControlVideoStabilizationMode.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/ControlVideoStabilizationMode.aidl
@@ -22,10 +22,7 @@
 
 package android.hardware.camera.metadata;
 
-/*
- * Enumeration definitions for the various entries that need them
- *
- *
+/**
  * android.control.videoStabilizationMode enumeration values
  * @see ANDROID_CONTROL_VIDEO_STABILIZATION_MODE
  */
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/LensPoseReference.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/LensPoseReference.aidl
index ca18676..3e6034b 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/LensPoseReference.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/LensPoseReference.aidl
@@ -32,4 +32,5 @@
     ANDROID_LENS_POSE_REFERENCE_PRIMARY_CAMERA,
     ANDROID_LENS_POSE_REFERENCE_GYROSCOPE,
     ANDROID_LENS_POSE_REFERENCE_UNDEFINED,
+    ANDROID_LENS_POSE_REFERENCE_AUTOMOTIVE,
 }
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableCapabilities.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableCapabilities.aidl
index 89f14ad..f5c77eb 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableCapabilities.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableCapabilities.aidl
@@ -48,4 +48,5 @@
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR,
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING,
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT,
+    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE,
 }
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableDynamicRangeProfilesMap.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableDynamicRangeProfilesMap.aidl
index c0ef8c6..f04fae3 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableDynamicRangeProfilesMap.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableDynamicRangeProfilesMap.aidl
@@ -27,19 +27,19 @@
  * @see ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
  */
 @VintfStability
-@Backing(type="int")
+@Backing(type="long")
 enum RequestAvailableDynamicRangeProfilesMap {
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD = 0x1,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10 = 0x2,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10 = 0x4,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS = 0x8,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF = 0x10,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO = 0x20,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM = 0x40,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO = 0x80,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF = 0x100,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO = 0x200,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM = 0x400,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO = 0x800,
-    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX = 0x1000,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD = 0x1L,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10 = 0x2L,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10 = 0x4L,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS = 0x8L,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF = 0x10L,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO = 0x20L,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM = 0x40L,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO = 0x80L,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF = 0x100L,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO = 0x200L,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM = 0x400L,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO = 0x800L,
+    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX = 0x1000L,
 }
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
index 19ebab5..daa0fd3 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
@@ -27,13 +27,13 @@
  * @see ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES
  */
 @VintfStability
-@Backing(type="int")
+@Backing(type="long")
 enum ScalerAvailableStreamUseCases {
-    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT = 0x0,
-    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW = 0x1,
-    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE = 0x2,
-    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD = 0x3,
-    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL = 0x4,
-    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL = 0x5,
-    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START = 0x10000,
+    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT = 0x0L,
+    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW = 0x1L,
+    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE = 0x2L,
+    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD = 0x3L,
+    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL = 0x4L,
+    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL = 0x5L,
+    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START = 0x10000L,
 }
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/SensorTestPatternMode.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/SensorTestPatternMode.aidl
index c9ca70a..29aede4 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/SensorTestPatternMode.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/SensorTestPatternMode.aidl
@@ -34,6 +34,6 @@
     ANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS,
     ANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY,
     ANDROID_SENSOR_TEST_PATTERN_MODE_PN9,
-    ANDROID_SENSOR_TEST_PATTERN_MODE_CUSTOM1 = 256,
     ANDROID_SENSOR_TEST_PATTERN_MODE_BLACK,
+    ANDROID_SENSOR_TEST_PATTERN_MODE_CUSTOM1 = 256,
 }
diff --git a/camera/provider/2.4/vts/OWNERS b/camera/provider/2.4/vts/OWNERS
index b8f6b04..eb4f0e4 100644
--- a/camera/provider/2.4/vts/OWNERS
+++ b/camera/provider/2.4/vts/OWNERS
@@ -1,3 +1,5 @@
+# Bug component: 41727
+
 # Camera team
 include platform/frameworks/av:/camera/OWNERS
 
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index 0e62265..2f24dfd 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -26,6 +26,7 @@
 cc_test {
     name: "VtsHalCameraProviderV2_4TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: ["VtsHalCameraProviderV2_4TargetTest.cpp"],
     srcs: ["VtsHalCameraProviderV2_4TargetTest.cpp"],
 
     // TODO(b/64437680): Assume these are always available on the device.
@@ -65,5 +66,9 @@
         "libhidlmemory",
         "libgralloctypes",
     ],
-    test_suites: ["general-tests", "vts"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+
 }
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 3254cf2..f89c71d 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -171,6 +171,27 @@
     int32_t format;
 };
 
+struct RecordingRateSizePair {
+    int32_t recordingRate;
+    int32_t width;
+    int32_t height;
+
+    bool operator==(const RecordingRateSizePair &p) const{
+        return p.recordingRate == recordingRate &&
+                p.width == width &&
+                p.height == height;
+    }
+};
+
+struct RecordingRateSizePairHasher {
+    size_t operator()(const RecordingRateSizePair& p) const {
+        std::size_t p1 = std::hash<int32_t>()(p.recordingRate);
+        std::size_t p2 = std::hash<int32_t>()(p.width);
+        std::size_t p3 = std::hash<int32_t>()(p.height);
+        return p1 ^ p2 ^ p3;
+    }
+};
+
 struct AvailableZSLInputOutput {
     int32_t inputFormat;
     int32_t outputFormat;
@@ -201,7 +222,7 @@
     HIDDEN_SECURE_CAMERA
 };
 
-const static std::vector<int32_t> kMandatoryUseCases = {
+const static std::vector<int64_t> kMandatoryUseCases = {
         ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
         ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW,
         ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE,
@@ -4540,6 +4561,39 @@
         rc = pickConstrainedModeSize(staticMeta, hfrStream);
         ASSERT_EQ(Status::OK, rc);
 
+        // Check that HAL does not advertise multiple preview rates
+        // for the same recording rate and size.
+        camera_metadata_ro_entry entry;
+
+        std::unordered_map<RecordingRateSizePair, int32_t, RecordingRateSizePairHasher> fpsRangeMap;
+
+        auto retCode = find_camera_metadata_ro_entry(staticMeta,
+                ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS, &entry);
+        ASSERT_EQ(retCode, 0);
+        ASSERT_GT(entry.count, 0);
+
+        for (size_t i = 0; i < entry.count; i+=5) {
+            RecordingRateSizePair recordingRateSizePair;
+            recordingRateSizePair.width = entry.data.i32[i];
+            recordingRateSizePair.height = entry.data.i32[i+1];
+
+            int32_t previewFps = entry.data.i32[i+2];
+            int32_t recordingFps = entry.data.i32[i+3];
+            recordingRateSizePair.recordingRate = recordingFps;
+
+            if (recordingFps != previewFps) {
+                auto it = fpsRangeMap.find(recordingRateSizePair);
+                if (it == fpsRangeMap.end()) {
+                    fpsRangeMap.insert(std::make_pair(recordingRateSizePair,previewFps));
+                    ALOGV("Added RecordingRateSizePair:%d , %d, %d PreviewRate: %d",
+                            recordingFps, recordingRateSizePair.width, recordingRateSizePair.height,
+                            previewFps);
+                } else {
+                    ASSERT_EQ(previewFps, it->second);
+                }
+            }
+        }
+
         int32_t streamId = 0;
         uint32_t streamConfigCounter = 0;
         V3_2::Stream stream = {streamId,
@@ -6941,16 +6995,16 @@
         ASSERT_NE(0u, outputPreviewStreams.size());
 
         // Combine valid and invalid stream use cases
-        std::vector<int32_t> useCases(kMandatoryUseCases);
+        std::vector<int64_t> useCases(kMandatoryUseCases);
         useCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL + 1);
 
-        std::vector<int32_t> supportedUseCases;
+        std::vector<int64_t> supportedUseCases;
         camera_metadata_ro_entry entry;
         auto retcode = find_camera_metadata_ro_entry(staticMeta,
                 ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES, &entry);
         if ((0 == retcode) && (entry.count > 0)) {
-            supportedUseCases.insert(supportedUseCases.end(), entry.data.i32,
-                    entry.data.i32 + entry.count);
+            supportedUseCases.insert(supportedUseCases.end(), entry.data.i64,
+                    entry.data.i64 + entry.count);
         } else {
             supportedUseCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
         }
@@ -6984,7 +7038,7 @@
                                                 });
         ASSERT_TRUE(ret.isOk());
 
-        for (int32_t useCase : useCases) {
+        for (int64_t useCase : useCases) {
             bool useCaseSupported = std::find(supportedUseCases.begin(),
                     supportedUseCases.end(), useCase) != supportedUseCases.end();
 
@@ -8233,21 +8287,21 @@
     ASSERT_NE(nullptr, staticMeta);
     ASSERT_NE(nullptr, profiles);
     camera_metadata_ro_entry entry;
-    std::unordered_set<int32_t> entries;
+    std::unordered_set<int64_t> entries;
     int rc = find_camera_metadata_ro_entry(staticMeta,
             ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP, &entry);
     ASSERT_EQ(rc, 0);
     ASSERT_TRUE(entry.count > 0);
-    ASSERT_EQ(entry.count % 2, 0);
+    ASSERT_EQ(entry.count % 3, 0);
 
-    for (uint32_t i = 0; i < entry.count; i += 2) {
-        ASSERT_NE(entry.data.i32[i],
+    for (uint32_t i = 0; i < entry.count; i += 3) {
+        ASSERT_NE(entry.data.i64[i],
                 ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
-        ASSERT_EQ(entries.find(entry.data.i32[i]), entries.end());
-        entries.insert(static_cast<int32_t>(entry.data.i32[i]));
+        ASSERT_EQ(entries.find(entry.data.i64[i]), entries.end());
+        entries.insert(entry.data.i64[i]);
         profiles->emplace_back(
                 static_cast<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap>
-                (entry.data.i32[i]));
+                (entry.data.i64[i]));
     }
 
     if (!entries.empty()) {
@@ -8281,7 +8335,7 @@
         bool smpte2094_40Present = importer.isSmpte2094_40Present(
                 b.buffer.buffer.getNativeHandle());
 
-        switch (static_cast<uint32_t>(profile)) {
+        switch (static_cast<int64_t>(profile)) {
             case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10:
                 ASSERT_FALSE(smpte2086Present);
                 ASSERT_FALSE(smpte2094_10Present);
@@ -8310,7 +8364,7 @@
                 ASSERT_FALSE(smpte2094_40Present);
                 break;
             default:
-                ALOGE("%s: Unexpected 10-bit dynamic range profile: %d",
+                ALOGE("%s: Unexpected 10-bit dynamic range profile: %" PRId64,
                         __FUNCTION__, profile);
                 ADD_FAILURE();
         }
@@ -9434,19 +9488,19 @@
     if ((0 == retcode) && (entry.count > 0)) {
         supportMandatoryUseCases = true;
         for (size_t i = 0; i < kMandatoryUseCases.size(); i++) {
-            if (std::find(entry.data.i32, entry.data.i32 + entry.count, kMandatoryUseCases[i])
-                    == entry.data.i32 + entry.count) {
+            if (std::find(entry.data.i64, entry.data.i64 + entry.count, kMandatoryUseCases[i])
+                    == entry.data.i64 + entry.count) {
                 supportMandatoryUseCases = false;
                 break;
             }
         }
         bool supportDefaultUseCase = false;
         for (size_t i = 0; i < entry.count; i++) {
-            if (entry.data.i32[i] == ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
+            if (entry.data.i64[i] == ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
                 supportDefaultUseCase = true;
             }
-            ASSERT_TRUE(entry.data.i32[i] <= ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL ||
-                    entry.data.i32[i] >= ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START);
+            ASSERT_TRUE(entry.data.i64[i] <= ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL ||
+                    entry.data.i64[i] >= ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START);
         }
         ASSERT_TRUE(supportDefaultUseCase);
     }
diff --git a/camera/provider/aidl/android/hardware/camera/provider/ConcurrentCameraIdCombination.aidl b/camera/provider/aidl/android/hardware/camera/provider/ConcurrentCameraIdCombination.aidl
index 7d8e486..46917a1 100644
--- a/camera/provider/aidl/android/hardware/camera/provider/ConcurrentCameraIdCombination.aidl
+++ b/camera/provider/aidl/android/hardware/camera/provider/ConcurrentCameraIdCombination.aidl
@@ -18,5 +18,9 @@
 
 @VintfStability
 parcelable ConcurrentCameraIdCombination {
+    /**
+     * Combination of camera ids, that can be opened
+     * and configured with sessions on, concurrently.
+     */
     List<String> combination;
 }
diff --git a/camera/provider/aidl/android/hardware/camera/provider/ICameraProvider.aidl b/camera/provider/aidl/android/hardware/camera/provider/ICameraProvider.aidl
index 7a4e010..c4eba8d 100644
--- a/camera/provider/aidl/android/hardware/camera/provider/ICameraProvider.aidl
+++ b/camera/provider/aidl/android/hardware/camera/provider/ICameraProvider.aidl
@@ -56,7 +56,6 @@
 
 @VintfStability
 interface ICameraProvider {
-
     /**
      * Device states to be passed to notifyDeviceStateChange().
      */
@@ -295,7 +294,7 @@
      *                configurations that need to be queried for support.
      *
      * On error, the service specific error for the operation will be, one of:
-     *     METHOD_NOT_SUPPORTED:
+     *     OPERATION_NOT_SUPPORTED:
      *          The camera provider does not support stream combination query.
      *     INTERNAL_ERROR:
      *          The stream combination query cannot complete due to internal
diff --git a/camera/provider/aidl/vts/Android.bp b/camera/provider/aidl/vts/Android.bp
new file mode 100644
index 0000000..727ef03
--- /dev/null
+++ b/camera/provider/aidl/vts/Android.bp
@@ -0,0 +1,75 @@
+//
+// 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_test {
+    name: "VtsAidlHalCameraProvider_TargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "camera_aidl_test.cpp",
+        "device_cb.cpp",
+        "empty_device_cb.cpp",
+        "simple_device_cb.cpp",
+        "torch_provider_cb.cpp",
+        "VtsAidlHalCameraProvider_TargetTest.cpp",
+    ],
+
+    // TODO(b/64437680): Assume these are always available on the device.
+    shared_libs: [
+        "libbinder_ndk",
+        "libcamera_metadata",
+        "libcutils",
+        "libfmq",
+        "libgui",
+        "libui",
+        "libbase",
+        "android.hardware.common-V2-ndk",
+        "android.hardware.common.fmq-V1-ndk",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
+    ],
+
+    // Statically link to libs not guaranteed to be present on the device.
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper",
+        "android.hardware.camera.common-V1-ndk",
+        "android.hardware.camera.device-V1-ndk",
+        "android.hardware.camera.metadata-V1-ndk",
+        "android.hardware.camera.provider-V1-ndk",
+        "android.hardware.graphics.common-V3-ndk",
+        "android.hidl.allocator@1.0",
+        "libgrallocusage",
+        "libhidlmemory",
+        "libgralloctypes",
+        "libaidlcommonsupport",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/camera/provider/aidl/vts/AndroidTest.xml b/camera/provider/aidl/vts/AndroidTest.xml
new file mode 100644
index 0000000..226121d
--- /dev/null
+++ b/camera/provider/aidl/vts/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VtsAidlHalCameraProvider_TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsAidlHalCameraProvider_TargetTest->/data/local/tmp/VtsAidlHalCameraProvider_TargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsAidlHalCameraProvider_TargetTest" />
+        <option name="native-test-timeout" value="1800000"/> <!-- 30 min -->
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/camera/provider/aidl/vts/OWNERS b/camera/provider/aidl/vts/OWNERS
new file mode 100644
index 0000000..27d370b
--- /dev/null
+++ b/camera/provider/aidl/vts/OWNERS
@@ -0,0 +1,6 @@
+# Camera team
+include platform/frameworks/av:/camera/OWNERS
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
\ No newline at end of file
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
new file mode 100644
index 0000000..af83578
--- /dev/null
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -0,0 +1,3065 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/camera/common/VendorTagSection.h>
+#include <aidl/android/hardware/camera/device/ICameraDevice.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <camera_aidl_test.h>
+#include <cutils/properties.h>
+#include <device_cb.h>
+#include <empty_device_cb.h>
+#include <grallocusage/GrallocUsageConversion.h>
+#include <gtest/gtest.h>
+#include <hardware/gralloc.h>
+#include <hardware/gralloc1.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+#include <torch_provider_cb.h>
+#include <list>
+
+using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
+using ::aidl::android::hardware::camera::common::CameraResourceCost;
+using ::aidl::android::hardware::camera::common::TorchModeStatus;
+using ::aidl::android::hardware::camera::common::VendorTagSection;
+using ::aidl::android::hardware::camera::device::ICameraDevice;
+using ::aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap;
+using ::aidl::android::hardware::camera::metadata::SensorPixelMode;
+using ::aidl::android::hardware::camera::provider::CameraIdAndStreamCombination;
+using ::aidl::android::hardware::camera::provider::ICameraProviderCallbackDefault;
+
+using ::ndk::ScopedAStatus;
+
+namespace {
+const int32_t kBurstFrameCount = 10;
+const uint32_t kMaxStillWidth = 2048;
+const uint32_t kMaxStillHeight = 1536;
+
+const int64_t kEmptyFlushTimeoutMSec = 200;
+
+const static std::vector<int64_t> kMandatoryUseCases = {
+        ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+        ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW,
+        ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE,
+        ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD,
+        ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL,
+        ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL};
+}  // namespace
+
+TEST_P(CameraAidlTest, getCameraIdList) {
+    std::vector<std::string> idList;
+    ScopedAStatus ret = mProvider->getCameraIdList(&idList);
+    ASSERT_TRUE(ret.isOk());
+
+    for (size_t i = 0; i < idList.size(); i++) {
+        ALOGI("Camera Id[%zu] is %s", i, idList[i].c_str());
+    }
+}
+
+// Test if ICameraProvider::getVendorTags returns Status::OK
+TEST_P(CameraAidlTest, getVendorTags) {
+    std::vector<VendorTagSection> vendorTags;
+    ScopedAStatus ret = mProvider->getVendorTags(&vendorTags);
+
+    ASSERT_TRUE(ret.isOk());
+    for (size_t i = 0; i < vendorTags.size(); i++) {
+        ALOGI("Vendor tag section %zu name %s", i, vendorTags[i].sectionName.c_str());
+        for (auto& tag : vendorTags[i].tags) {
+            ALOGI("Vendor tag id %u name %s type %d", tag.tagId, tag.tagName.c_str(),
+                  (int)tag.tagType);
+        }
+    }
+}
+
+// Test if ICameraProvider::setCallback returns Status::OK
+TEST_P(CameraAidlTest, setCallback) {
+    struct ProviderCb : public ICameraProviderCallbackDefault {
+        ScopedAStatus cameraDeviceStatusChange(const std::string& cameraDeviceName,
+                                               CameraDeviceStatus newStatus) override {
+            ALOGI("camera device status callback name %s, status %d", cameraDeviceName.c_str(),
+                  (int)newStatus);
+            return ScopedAStatus::ok();
+        }
+        ScopedAStatus torchModeStatusChange(const std::string& cameraDeviceName,
+                                            TorchModeStatus newStatus) override {
+            ALOGI("Torch mode status callback name %s, status %d", cameraDeviceName.c_str(),
+                  (int)newStatus);
+            return ScopedAStatus::ok();
+        }
+        ScopedAStatus physicalCameraDeviceStatusChange(const std::string& cameraDeviceName,
+                                                       const std::string& physicalCameraDeviceName,
+                                                       CameraDeviceStatus newStatus) override {
+            ALOGI("physical camera device status callback name %s, physical camera name %s,"
+                  " status %d",
+                  cameraDeviceName.c_str(), physicalCameraDeviceName.c_str(), (int)newStatus);
+            return ScopedAStatus::ok();
+        }
+    };
+
+    std::shared_ptr<ProviderCb> cb = ProviderCb::make<ProviderCb>();
+    ScopedAStatus ret = mProvider->setCallback(cb);
+    ASSERT_TRUE(ret.isOk());
+    ret = mProvider->setCallback(nullptr);
+    ASSERT_TRUE(ret.isOk());
+}
+
+// Test if ICameraProvider::getCameraDeviceInterface returns Status::OK and non-null device
+TEST_P(CameraAidlTest, getCameraDeviceInterface) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+
+    for (const auto& name : cameraDeviceNames) {
+        std::shared_ptr<ICameraDevice> cameraDevice;
+        ScopedAStatus ret = mProvider->getCameraDeviceInterface(name, &cameraDevice);
+        ALOGI("getCameraDeviceInterface returns: %d:%d", ret.getExceptionCode(),
+              ret.getServiceSpecificError());
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_NE(cameraDevice, nullptr);
+    }
+}
+
+// Verify that the device resource cost can be retrieved and the values are
+// correct.
+TEST_P(CameraAidlTest, getResourceCost) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+
+    for (const auto& deviceName : cameraDeviceNames) {
+        std::shared_ptr<ICameraDevice> cameraDevice;
+        ScopedAStatus ret = mProvider->getCameraDeviceInterface(deviceName, &cameraDevice);
+        ALOGI("getCameraDeviceInterface returns: %d:%d", ret.getExceptionCode(),
+              ret.getServiceSpecificError());
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_NE(cameraDevice, nullptr);
+
+        CameraResourceCost resourceCost;
+        ret = cameraDevice->getResourceCost(&resourceCost);
+        ALOGI("getResourceCost returns: %d:%d", ret.getExceptionCode(),
+              ret.getServiceSpecificError());
+        ASSERT_TRUE(ret.isOk());
+
+        ALOGI("    Resource cost is %d", resourceCost.resourceCost);
+        ASSERT_LE(resourceCost.resourceCost, 100u);
+
+        for (const auto& name : resourceCost.conflictingDevices) {
+            ALOGI("    Conflicting device: %s", name.c_str());
+        }
+    }
+}
+
+TEST_P(CameraAidlTest, systemCameraTest) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::map<std::string, std::vector<SystemCameraKind>> hiddenPhysicalIdToLogicalMap;
+    for (const auto& name : cameraDeviceNames) {
+        std::shared_ptr<ICameraDevice> device;
+        ALOGI("systemCameraTest: Testing camera device %s", name.c_str());
+        ndk::ScopedAStatus ret = mProvider->getCameraDeviceInterface(name, &device);
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_NE(device, nullptr);
+
+        CameraMetadata cameraCharacteristics;
+        ret = device->getCameraCharacteristics(&cameraCharacteristics);
+        ASSERT_TRUE(ret.isOk());
+
+        const camera_metadata_t* staticMeta =
+                reinterpret_cast<const camera_metadata_t*>(cameraCharacteristics.metadata.data());
+        Status rc = isLogicalMultiCamera(staticMeta);
+        if (rc == Status::OPERATION_NOT_SUPPORTED) {
+            return;
+        }
+
+        ASSERT_EQ(rc, Status::OK);
+        std::unordered_set<std::string> physicalIds;
+        ASSERT_EQ(getPhysicalCameraIds(staticMeta, &physicalIds), Status::OK);
+        SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
+        Status retStatus = getSystemCameraKind(staticMeta, &systemCameraKind);
+        ASSERT_EQ(retStatus, Status::OK);
+
+        for (auto physicalId : physicalIds) {
+            bool isPublicId = false;
+            for (auto& deviceName : cameraDeviceNames) {
+                std::string publicVersion, publicId;
+                ASSERT_TRUE(matchDeviceName(deviceName, mProviderType, &publicVersion, &publicId));
+                if (physicalId == publicId) {
+                    isPublicId = true;
+                    break;
+                }
+            }
+
+            // For hidden physical cameras, collect their associated logical cameras
+            // and store the system camera kind.
+            if (!isPublicId) {
+                auto it = hiddenPhysicalIdToLogicalMap.find(physicalId);
+                if (it == hiddenPhysicalIdToLogicalMap.end()) {
+                    hiddenPhysicalIdToLogicalMap.insert(std::make_pair(
+                            physicalId, std::vector<SystemCameraKind>({systemCameraKind})));
+                } else {
+                    it->second.push_back(systemCameraKind);
+                }
+            }
+        }
+    }
+
+    // Check that the system camera kind of the logical cameras associated with
+    // each hidden physical camera is the same.
+    for (const auto& it : hiddenPhysicalIdToLogicalMap) {
+        SystemCameraKind neededSystemCameraKind = it.second.front();
+        for (auto foundSystemCamera : it.second) {
+            ASSERT_EQ(neededSystemCameraKind, foundSystemCamera);
+        }
+    }
+}
+
+// Verify that the static camera characteristics can be retrieved
+// successfully.
+TEST_P(CameraAidlTest, getCameraCharacteristics) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+
+    for (const auto& name : cameraDeviceNames) {
+        std::shared_ptr<ICameraDevice> device;
+        ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
+        ndk::ScopedAStatus ret = mProvider->getCameraDeviceInterface(name, &device);
+        ALOGI("getCameraDeviceInterface returns: %d:%d", ret.getExceptionCode(),
+              ret.getServiceSpecificError());
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_NE(device, nullptr);
+
+        CameraMetadata chars;
+        ret = device->getCameraCharacteristics(&chars);
+        ASSERT_TRUE(ret.isOk());
+        verifyCameraCharacteristics(chars);
+        verifyMonochromeCharacteristics(chars);
+        verifyRecommendedConfigs(chars);
+        verifyLogicalOrUltraHighResCameraMetadata(name, device, chars, cameraDeviceNames);
+
+        ASSERT_TRUE(ret.isOk());
+
+        // getPhysicalCameraCharacteristics will fail for publicly
+        // advertised camera IDs.
+        std::string version, cameraId;
+        ASSERT_TRUE(matchDeviceName(name, mProviderType, &version, &cameraId));
+        CameraMetadata devChars;
+        ret = device->getPhysicalCameraCharacteristics(cameraId, &devChars);
+        ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT), ret.getServiceSpecificError());
+        ASSERT_EQ(0, devChars.metadata.size());
+    }
+}
+
+// Verify that the torch strength level can be set and retrieved successfully.
+TEST_P(CameraAidlTest, turnOnTorchWithStrengthLevel) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+
+    std::shared_ptr<TorchProviderCb> cb = ndk::SharedRefBase::make<TorchProviderCb>(this);
+    ndk::ScopedAStatus ret = mProvider->setCallback(cb);
+    ASSERT_TRUE(ret.isOk());
+
+    for (const auto& name : cameraDeviceNames) {
+        int32_t defaultLevel;
+        std::shared_ptr<ICameraDevice> device;
+        ALOGI("%s: Testing camera device %s", __FUNCTION__, name.c_str());
+
+        ret = mProvider->getCameraDeviceInterface(name, &device);
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_NE(device, nullptr);
+
+        CameraMetadata chars;
+        ret = device->getCameraCharacteristics(&chars);
+        ASSERT_TRUE(ret.isOk());
+
+        const camera_metadata_t* staticMeta =
+                reinterpret_cast<const camera_metadata_t*>(chars.metadata.data());
+        bool torchStrengthControlSupported = isTorchStrengthControlSupported(staticMeta);
+        camera_metadata_ro_entry entry;
+        int rc = find_camera_metadata_ro_entry(staticMeta,
+                                               ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL, &entry);
+        if (torchStrengthControlSupported) {
+            ASSERT_EQ(rc, 0);
+            ASSERT_GT(entry.count, 0);
+            defaultLevel = *entry.data.i32;
+            ALOGI("Default level is:%d", defaultLevel);
+        }
+
+        mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
+        ret = device->turnOnTorchWithStrengthLevel(2);
+        ALOGI("turnOnTorchWithStrengthLevel returns status: %d", ret.getServiceSpecificError());
+        // OPERATION_NOT_SUPPORTED check
+        if (!torchStrengthControlSupported) {
+            ALOGI("Torch strength control not supported.");
+            ASSERT_EQ(static_cast<int32_t>(Status::OPERATION_NOT_SUPPORTED),
+                      ret.getServiceSpecificError());
+        } else {
+            {
+                ASSERT_TRUE(ret.isOk());
+                std::unique_lock<std::mutex> l(mTorchLock);
+                while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+                    auto timeout = std::chrono::system_clock::now() +
+                                   std::chrono::seconds(kTorchTimeoutSec);
+                    ASSERT_NE(std::cv_status::timeout, mTorchCond.wait_until(l, timeout));
+                }
+                ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus);
+                mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
+            }
+            ALOGI("getTorchStrengthLevel: Testing");
+            int32_t strengthLevel;
+            ret = device->getTorchStrengthLevel(&strengthLevel);
+            ASSERT_TRUE(ret.isOk());
+            ALOGI("Torch strength level is : %d", strengthLevel);
+            ASSERT_EQ(strengthLevel, 2);
+
+            // Turn OFF the torch and verify torch strength level is reset to default level.
+            ALOGI("Testing torch strength level reset after turning the torch OFF.");
+            ret = device->setTorchMode(false);
+            ASSERT_TRUE(ret.isOk());
+            {
+                std::unique_lock<std::mutex> l(mTorchLock);
+                while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+                    auto timeout = std::chrono::system_clock::now() +
+                                   std::chrono::seconds(kTorchTimeoutSec);
+                    ASSERT_NE(std::cv_status::timeout, mTorchCond.wait_until(l, timeout));
+                }
+                ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, mTorchStatus);
+            }
+
+            ret = device->getTorchStrengthLevel(&strengthLevel);
+            ASSERT_TRUE(ret.isOk());
+            ALOGI("Torch strength level after turning OFF torch is : %d", strengthLevel);
+            ASSERT_EQ(strengthLevel, defaultLevel);
+        }
+    }
+}
+
+// In case it is supported verify that torch can be enabled.
+// Check for corresponding torch callbacks as well.
+TEST_P(CameraAidlTest, setTorchMode) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+
+    std::shared_ptr<TorchProviderCb> cb = ndk::SharedRefBase::make<TorchProviderCb>(this);
+    ndk::ScopedAStatus ret = mProvider->setCallback(cb);
+    ALOGI("setCallback returns status: %d", ret.getServiceSpecificError());
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_NE(cb, nullptr);
+
+    for (const auto& name : cameraDeviceNames) {
+        std::shared_ptr<ICameraDevice> device;
+        ALOGI("setTorchMode: Testing camera device %s", name.c_str());
+        ret = mProvider->getCameraDeviceInterface(name, &device);
+        ALOGI("getCameraDeviceInterface returns status:%d:%d", ret.getExceptionCode(),
+              ret.getServiceSpecificError());
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_NE(device, nullptr);
+
+        CameraMetadata metadata;
+        ret = device->getCameraCharacteristics(&metadata);
+        ALOGI("getCameraCharacteristics returns status:%d", ret.getServiceSpecificError());
+        ASSERT_TRUE(ret.isOk());
+        camera_metadata_t* staticMeta =
+                reinterpret_cast<camera_metadata_t*>(metadata.metadata.data());
+        bool torchSupported = isTorchSupported(staticMeta);
+
+        mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
+        ret = device->setTorchMode(true);
+        ALOGI("setTorchMode returns status: %d", ret.getServiceSpecificError());
+        if (!torchSupported) {
+            ASSERT_EQ(static_cast<int32_t>(Status::OPERATION_NOT_SUPPORTED),
+                      ret.getServiceSpecificError());
+        } else {
+            ASSERT_TRUE(ret.isOk());
+            {
+                std::unique_lock<std::mutex> l(mTorchLock);
+                while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+                    auto timeout = std::chrono::system_clock::now() +
+                                   std::chrono::seconds(kTorchTimeoutSec);
+                    ASSERT_NE(std::cv_status::timeout, mTorchCond.wait_until(l, timeout));
+                }
+                ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus);
+                mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
+            }
+
+            ret = device->setTorchMode(false);
+            ASSERT_TRUE(ret.isOk());
+            {
+                std::unique_lock<std::mutex> l(mTorchLock);
+                while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+                    auto timeout = std::chrono::system_clock::now() +
+                                   std::chrono::seconds(kTorchTimeoutSec);
+                    ASSERT_NE(std::cv_status::timeout, mTorchCond.wait_until(l, timeout));
+                }
+                ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, mTorchStatus);
+            }
+        }
+    }
+
+    ret = mProvider->setCallback(nullptr);
+    ASSERT_TRUE(ret.isOk());
+}
+
+// Check dump functionality.
+TEST_P(CameraAidlTest, dump) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+
+    for (const auto& name : cameraDeviceNames) {
+        std::shared_ptr<ICameraDevice> device;
+        ALOGI("dump: Testing camera device %s", name.c_str());
+
+        ndk::ScopedAStatus ret = mProvider->getCameraDeviceInterface(name, &device);
+        ALOGI("getCameraDeviceInterface returns status:%d:%d", ret.getExceptionCode(),
+              ret.getServiceSpecificError());
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_NE(device, nullptr);
+
+        int raw_handle = open(kDumpOutput, O_RDWR);
+        ASSERT_GE(raw_handle, 0);
+
+        auto retStatus = device->dump(raw_handle, nullptr, 0);
+        ASSERT_EQ(retStatus, ::android::OK);
+        close(raw_handle);
+    }
+}
+
+// Open, dump, then close
+TEST_P(CameraAidlTest, openClose) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+
+    for (const auto& name : cameraDeviceNames) {
+        std::shared_ptr<ICameraDevice> device;
+        ALOGI("openClose: Testing camera device %s", name.c_str());
+        ndk::ScopedAStatus ret = mProvider->getCameraDeviceInterface(name, &device);
+        ALOGI("getCameraDeviceInterface returns status:%d:%d", ret.getExceptionCode(),
+              ret.getServiceSpecificError());
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_NE(device, nullptr);
+
+        std::shared_ptr<EmptyDeviceCb> cb = ndk::SharedRefBase::make<EmptyDeviceCb>();
+
+        ret = device->open(cb, &mSession);
+        ASSERT_TRUE(ret.isOk());
+        ALOGI("device::open returns status:%d:%d", ret.getExceptionCode(),
+              ret.getServiceSpecificError());
+        ASSERT_NE(mSession, nullptr);
+        int raw_handle = open(kDumpOutput, O_RDWR);
+        ASSERT_GE(raw_handle, 0);
+
+        auto retStatus = device->dump(raw_handle, nullptr, 0);
+        ASSERT_EQ(retStatus, ::android::OK);
+        close(raw_handle);
+
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+        // TODO: test all session API calls return INTERNAL_ERROR after close
+        // TODO: keep a wp copy here and verify session cannot be promoted out of this scope
+    }
+}
+
+// Check whether all common default request settings can be successfully
+// constructed.
+TEST_P(CameraAidlTest, constructDefaultRequestSettings) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+
+    for (const auto& name : cameraDeviceNames) {
+        std::shared_ptr<ICameraDevice> device;
+        ALOGI("constructDefaultRequestSettings: Testing camera device %s", name.c_str());
+        ndk::ScopedAStatus ret = mProvider->getCameraDeviceInterface(name, &device);
+        ALOGI("getCameraDeviceInterface returns status:%d:%d", ret.getExceptionCode(),
+              ret.getServiceSpecificError());
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_NE(device, nullptr);
+
+        std::shared_ptr<EmptyDeviceCb> cb = ndk::SharedRefBase::make<EmptyDeviceCb>();
+        ret = device->open(cb, &mSession);
+        ALOGI("device::open returns status:%d:%d", ret.getExceptionCode(),
+              ret.getServiceSpecificError());
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_NE(mSession, nullptr);
+
+        for (int32_t t = (int32_t)RequestTemplate::PREVIEW; t <= (int32_t)RequestTemplate::MANUAL;
+             t++) {
+            RequestTemplate reqTemplate = (RequestTemplate)t;
+            CameraMetadata rawMetadata;
+            ret = mSession->constructDefaultRequestSettings(reqTemplate, &rawMetadata);
+            ALOGI("constructDefaultRequestSettings returns status:%d:%d", ret.getExceptionCode(),
+                  ret.getServiceSpecificError());
+
+            if (reqTemplate == RequestTemplate::ZERO_SHUTTER_LAG ||
+                reqTemplate == RequestTemplate::MANUAL) {
+                // optional templates
+                ASSERT_TRUE(ret.isOk() || static_cast<int32_t>(Status::ILLEGAL_ARGUMENT) ==
+                                                  ret.getServiceSpecificError());
+            } else {
+                ASSERT_TRUE(ret.isOk());
+            }
+
+            if (ret.isOk()) {
+                const camera_metadata_t* metadata = (camera_metadata_t*)rawMetadata.metadata.data();
+                size_t expectedSize = rawMetadata.metadata.size();
+                int result = validate_camera_metadata_structure(metadata, &expectedSize);
+                ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+                verifyRequestTemplate(metadata, reqTemplate);
+            } else {
+                ASSERT_EQ(0u, rawMetadata.metadata.size());
+            }
+        }
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Verify that all supported stream formats and sizes can be configured
+// successfully.
+TEST_P(CameraAidlTest, configureStreamsAvailableOutputs) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::vector<AvailableStream> outputStreams;
+
+    for (const auto& name : cameraDeviceNames) {
+        CameraMetadata meta;
+        std::shared_ptr<ICameraDevice> device;
+
+        openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/, &device /*out*/);
+
+        camera_metadata_t* staticMeta = reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
+        outputStreams.clear();
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
+        ASSERT_NE(0u, outputStreams.size());
+
+        int32_t jpegBufferSize = 0;
+        ASSERT_EQ(Status::OK, getJpegBufferSize(staticMeta, &jpegBufferSize));
+        ASSERT_NE(0u, jpegBufferSize);
+
+        int32_t streamId = 0;
+        int32_t streamConfigCounter = 0;
+        for (auto& it : outputStreams) {
+            Stream stream;
+            Dataspace dataspace = getDataspace(static_cast<PixelFormat>(it.format));
+            stream.id = streamId;
+            stream.streamType = StreamType::OUTPUT;
+            stream.width = it.width;
+            stream.height = it.height;
+            stream.format = static_cast<PixelFormat>(it.format);
+            stream.dataSpace = dataspace;
+            stream.usage = static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                    GRALLOC1_CONSUMER_USAGE_HWCOMPOSER);
+            stream.rotation = StreamRotation::ROTATION_0;
+            stream.dynamicRangeProfile = RequestAvailableDynamicRangeProfilesMap::
+                    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD;
+
+            std::vector<Stream> streams = {stream};
+            StreamConfiguration config;
+            createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
+                                      jpegBufferSize);
+
+            bool expectStreamCombQuery = (isLogicalMultiCamera(staticMeta) == Status::OK);
+            verifyStreamCombination(device, config, /*expectedStatus*/ true, expectStreamCombQuery);
+
+            config.streamConfigCounter = streamConfigCounter++;
+            std::vector<HalStream> halConfigs;
+            ndk::ScopedAStatus ret = mSession->configureStreams(config, &halConfigs);
+            ASSERT_TRUE(ret.isOk());
+            ASSERT_EQ(halConfigs.size(), 1);
+            ASSERT_EQ(halConfigs[0].id, streamId);
+
+            streamId++;
+        }
+
+        ndk::ScopedAStatus ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Verify that mandatory concurrent streams and outputs are supported.
+TEST_P(CameraAidlTest, configureConcurrentStreamsAvailableOutputs) {
+    struct CameraTestInfo {
+        CameraMetadata staticMeta;
+        std::shared_ptr<ICameraDeviceSession> session;
+        std::shared_ptr<ICameraDevice> cameraDevice;
+        StreamConfiguration config;
+    };
+
+    std::map<std::string, std::string> idToNameMap = getCameraDeviceIdToNameMap(mProvider);
+    std::vector<ConcurrentCameraIdCombination> concurrentDeviceCombinations =
+            getConcurrentDeviceCombinations(mProvider);
+    std::vector<AvailableStream> outputStreams;
+    for (const auto& cameraDeviceIds : concurrentDeviceCombinations) {
+        std::vector<CameraIdAndStreamCombination> cameraIdsAndStreamCombinations;
+        std::vector<CameraTestInfo> cameraTestInfos;
+        size_t i = 0;
+        for (const auto& id : cameraDeviceIds.combination) {
+            CameraTestInfo cti;
+            auto it = idToNameMap.find(id);
+            ASSERT_TRUE(idToNameMap.end() != it);
+            std::string name = it->second;
+
+            openEmptyDeviceSession(name, mProvider, &cti.session /*out*/, &cti.staticMeta /*out*/,
+                                   &cti.cameraDevice /*out*/);
+
+            outputStreams.clear();
+            camera_metadata_t* staticMeta =
+                    reinterpret_cast<camera_metadata_t*>(cti.staticMeta.metadata.data());
+            ASSERT_EQ(Status::OK, getMandatoryConcurrentStreams(staticMeta, &outputStreams));
+            ASSERT_NE(0u, outputStreams.size());
+
+            int32_t jpegBufferSize = 0;
+            ASSERT_EQ(Status::OK, getJpegBufferSize(staticMeta, &jpegBufferSize));
+            ASSERT_NE(0u, jpegBufferSize);
+
+            int32_t streamId = 0;
+            std::vector<Stream> streams(outputStreams.size());
+            size_t j = 0;
+            for (const auto& s : outputStreams) {
+                Stream stream;
+                Dataspace dataspace = getDataspace(static_cast<PixelFormat>(s.format));
+                stream.id = streamId++;
+                stream.streamType = StreamType::OUTPUT;
+                stream.width = s.width;
+                stream.height = s.height;
+                stream.format = static_cast<PixelFormat>(s.format);
+                stream.usage = static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                        GRALLOC1_CONSUMER_USAGE_HWCOMPOSER);
+                stream.dataSpace = dataspace;
+                stream.rotation = StreamRotation::ROTATION_0;
+                stream.sensorPixelModesUsed = {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT};
+                stream.dynamicRangeProfile = RequestAvailableDynamicRangeProfilesMap::
+                        ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD;
+                streams[j] = stream;
+                j++;
+            }
+
+            // Add the created stream configs to cameraIdsAndStreamCombinations
+            createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &cti.config,
+                                      jpegBufferSize);
+
+            cti.config.streamConfigCounter = outputStreams.size();
+            CameraIdAndStreamCombination cameraIdAndStreamCombination;
+            cameraIdAndStreamCombination.cameraId = id;
+            cameraIdAndStreamCombination.streamConfiguration = cti.config;
+            cameraIdsAndStreamCombinations.push_back(cameraIdAndStreamCombination);
+            i++;
+            cameraTestInfos.push_back(cti);
+        }
+        // Now verify that concurrent streams are supported
+        bool combinationSupported;
+        ndk::ScopedAStatus ret = mProvider->isConcurrentStreamCombinationSupported(
+                cameraIdsAndStreamCombinations, &combinationSupported);
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(combinationSupported, true);
+
+        // Test the stream can actually be configured
+        for (auto& cti : cameraTestInfos) {
+            if (cti.session != nullptr) {
+                camera_metadata_t* staticMeta =
+                        reinterpret_cast<camera_metadata_t*>(cti.staticMeta.metadata.data());
+                bool expectStreamCombQuery = (isLogicalMultiCamera(staticMeta) == Status::OK);
+                verifyStreamCombination(cti.cameraDevice, cti.config, /*expectedStatus*/ true,
+                                        expectStreamCombQuery);
+            }
+
+            if (cti.session != nullptr) {
+                std::vector<HalStream> streamConfigs;
+                ret = cti.session->configureStreams(cti.config, &streamConfigs);
+                ASSERT_TRUE(ret.isOk());
+                ASSERT_EQ(cti.config.streams.size(), streamConfigs.size());
+            }
+        }
+
+        for (auto& cti : cameraTestInfos) {
+            ret = cti.session->close();
+            ASSERT_TRUE(ret.isOk());
+        }
+    }
+}
+
+// Check for correct handling of invalid/incorrect configuration parameters.
+TEST_P(CameraAidlTest, configureStreamsInvalidOutputs) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::vector<AvailableStream> outputStreams;
+
+    for (const auto& name : cameraDeviceNames) {
+        CameraMetadata meta;
+        std::shared_ptr<ICameraDevice> cameraDevice;
+
+        openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+                               &cameraDevice /*out*/);
+        camera_metadata_t* staticMeta = reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
+        outputStreams.clear();
+
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
+        ASSERT_NE(0u, outputStreams.size());
+
+        int32_t jpegBufferSize = 0;
+        ASSERT_EQ(Status::OK, getJpegBufferSize(staticMeta, &jpegBufferSize));
+        ASSERT_NE(0u, jpegBufferSize);
+
+        int32_t streamId = 0;
+        Stream stream = {streamId++,
+                         StreamType::OUTPUT,
+                         static_cast<uint32_t>(0),
+                         static_cast<uint32_t>(0),
+                         static_cast<PixelFormat>(outputStreams[0].format),
+                         static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                                 GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
+                         Dataspace::UNKNOWN,
+                         StreamRotation::ROTATION_0,
+                         std::string(),
+                         jpegBufferSize,
+                         -1,
+                         {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                         RequestAvailableDynamicRangeProfilesMap::
+                                 ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+        int32_t streamConfigCounter = 0;
+        std::vector<Stream> streams = {stream};
+        StreamConfiguration config;
+        createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
+                                  jpegBufferSize);
+
+        verifyStreamCombination(cameraDevice, config, /*expectedStatus*/ false,
+                                /*expectStreamCombQuery*/ false);
+
+        config.streamConfigCounter = streamConfigCounter++;
+        std::vector<HalStream> halConfigs;
+        ndk::ScopedAStatus ret = mSession->configureStreams(config, &halConfigs);
+        ASSERT_TRUE(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT) ==
+                            ret.getServiceSpecificError() ||
+                    static_cast<int32_t>(Status::INTERNAL_ERROR) == ret.getServiceSpecificError());
+
+        stream = {streamId++,
+                  StreamType::OUTPUT,
+                  /*width*/ INT32_MAX,
+                  /*height*/ INT32_MAX,
+                  static_cast<PixelFormat>(outputStreams[0].format),
+                  static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                          GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
+                  Dataspace::UNKNOWN,
+                  StreamRotation::ROTATION_0,
+                  std::string(),
+                  jpegBufferSize,
+                  -1,
+                  {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                  RequestAvailableDynamicRangeProfilesMap::
+                          ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+
+        streams[0] = stream;
+        createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
+                                  jpegBufferSize);
+
+        config.streamConfigCounter = streamConfigCounter++;
+        halConfigs.clear();
+        ret = mSession->configureStreams(config, &halConfigs);
+        ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT), ret.getServiceSpecificError());
+
+        for (auto& it : outputStreams) {
+            stream = {streamId++,
+                      StreamType::OUTPUT,
+                      it.width,
+                      it.height,
+                      static_cast<PixelFormat>(UINT32_MAX),
+                      static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                              GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
+                      Dataspace::UNKNOWN,
+                      StreamRotation::ROTATION_0,
+                      std::string(),
+                      jpegBufferSize,
+                      -1,
+                      {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                      RequestAvailableDynamicRangeProfilesMap::
+                              ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+
+            streams[0] = stream;
+            createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
+                                      jpegBufferSize);
+            config.streamConfigCounter = streamConfigCounter++;
+            halConfigs.clear();
+            ret = mSession->configureStreams(config, &halConfigs);
+            ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT),
+                      ret.getServiceSpecificError());
+
+            stream = {streamId++,
+                      StreamType::OUTPUT,
+                      it.width,
+                      it.height,
+                      static_cast<PixelFormat>(it.format),
+                      static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                              GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
+                      Dataspace::UNKNOWN,
+                      static_cast<StreamRotation>(UINT32_MAX),
+                      std::string(),
+                      jpegBufferSize,
+                      -1,
+                      {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                      RequestAvailableDynamicRangeProfilesMap::
+                              ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+
+            streams[0] = stream;
+            createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
+                                      jpegBufferSize);
+
+            config.streamConfigCounter = streamConfigCounter++;
+            halConfigs.clear();
+            ret = mSession->configureStreams(config, &halConfigs);
+            ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT),
+                      ret.getServiceSpecificError());
+        }
+
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Check whether all supported ZSL output stream combinations can be
+// configured successfully.
+TEST_P(CameraAidlTest, configureStreamsZSLInputOutputs) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::vector<AvailableStream> inputStreams;
+    std::vector<AvailableZSLInputOutput> inputOutputMap;
+
+    for (const auto& name : cameraDeviceNames) {
+        CameraMetadata meta;
+        std::shared_ptr<ICameraDevice> cameraDevice;
+
+        openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+                               &cameraDevice /*out*/);
+        camera_metadata_t* staticMeta = reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
+
+        Status rc = isZSLModeAvailable(staticMeta);
+        if (Status::OPERATION_NOT_SUPPORTED == rc) {
+            ndk::ScopedAStatus ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+        ASSERT_EQ(Status::OK, rc);
+
+        inputStreams.clear();
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, inputStreams));
+        ASSERT_NE(0u, inputStreams.size());
+
+        inputOutputMap.clear();
+        ASSERT_EQ(Status::OK, getZSLInputOutputMap(staticMeta, inputOutputMap));
+        ASSERT_NE(0u, inputOutputMap.size());
+
+        bool supportMonoY8 = false;
+        if (Status::OK == isMonochromeCamera(staticMeta)) {
+            for (auto& it : inputStreams) {
+                if (it.format == static_cast<uint32_t>(PixelFormat::Y8)) {
+                    supportMonoY8 = true;
+                    break;
+                }
+            }
+        }
+
+        int32_t jpegBufferSize = 0;
+        ASSERT_EQ(Status::OK, getJpegBufferSize(staticMeta, &jpegBufferSize));
+        ASSERT_NE(0u, jpegBufferSize);
+
+        int32_t streamId = 0;
+        bool hasPrivToY8 = false, hasY8ToY8 = false, hasY8ToBlob = false;
+        uint32_t streamConfigCounter = 0;
+        for (auto& inputIter : inputOutputMap) {
+            AvailableStream input;
+            ASSERT_EQ(Status::OK, findLargestSize(inputStreams, inputIter.inputFormat, input));
+            ASSERT_NE(0u, inputStreams.size());
+
+            if (inputIter.inputFormat ==
+                        static_cast<uint32_t>(PixelFormat::IMPLEMENTATION_DEFINED) &&
+                inputIter.outputFormat == static_cast<uint32_t>(PixelFormat::Y8)) {
+                hasPrivToY8 = true;
+            } else if (inputIter.inputFormat == static_cast<uint32_t>(PixelFormat::Y8)) {
+                if (inputIter.outputFormat == static_cast<uint32_t>(PixelFormat::BLOB)) {
+                    hasY8ToBlob = true;
+                } else if (inputIter.outputFormat == static_cast<uint32_t>(PixelFormat::Y8)) {
+                    hasY8ToY8 = true;
+                }
+            }
+            AvailableStream outputThreshold = {INT32_MAX, INT32_MAX, inputIter.outputFormat};
+            std::vector<AvailableStream> outputStreams;
+            ASSERT_EQ(Status::OK,
+                      getAvailableOutputStreams(staticMeta, outputStreams, &outputThreshold));
+            for (auto& outputIter : outputStreams) {
+                Dataspace outputDataSpace =
+                        getDataspace(static_cast<PixelFormat>(outputIter.format));
+                Stream zslStream = {
+                        streamId++,
+                        StreamType::OUTPUT,
+                        input.width,
+                        input.height,
+                        static_cast<PixelFormat>(input.format),
+                        static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                                GRALLOC_USAGE_HW_CAMERA_ZSL),
+                        Dataspace::UNKNOWN,
+                        StreamRotation::ROTATION_0,
+                        std::string(),
+                        jpegBufferSize,
+                        -1,
+                        {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                        RequestAvailableDynamicRangeProfilesMap::
+                                ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+                Stream inputStream = {
+                        streamId++,
+                        StreamType::INPUT,
+                        input.width,
+                        input.height,
+                        static_cast<PixelFormat>(input.format),
+                        static_cast<aidl::android::hardware::graphics::common::BufferUsage>(0),
+                        Dataspace::UNKNOWN,
+                        StreamRotation::ROTATION_0,
+                        std::string(),
+                        jpegBufferSize,
+                        -1,
+                        {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                        RequestAvailableDynamicRangeProfilesMap::
+                                ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+                Stream outputStream = {
+                        streamId++,
+                        StreamType::OUTPUT,
+                        outputIter.width,
+                        outputIter.height,
+                        static_cast<PixelFormat>(outputIter.format),
+                        static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                                GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
+                        outputDataSpace,
+                        StreamRotation::ROTATION_0,
+                        std::string(),
+                        jpegBufferSize,
+                        -1,
+                        {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                        RequestAvailableDynamicRangeProfilesMap::
+                                ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+
+                std::vector<Stream> streams = {inputStream, zslStream, outputStream};
+
+                StreamConfiguration config;
+                createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
+                                          jpegBufferSize);
+
+                verifyStreamCombination(cameraDevice, config, /*expectedStatus*/ true,
+                                        /*expectStreamCombQuery*/ false);
+
+                config.streamConfigCounter = streamConfigCounter++;
+                std::vector<HalStream> halConfigs;
+                ndk::ScopedAStatus ret = mSession->configureStreams(config, &halConfigs);
+                ASSERT_TRUE(ret.isOk());
+                ASSERT_EQ(3u, halConfigs.size());
+            }
+        }
+
+        if (supportMonoY8) {
+            if (Status::OK == isZSLModeAvailable(staticMeta, PRIV_REPROCESS)) {
+                ASSERT_TRUE(hasPrivToY8);
+            }
+            if (Status::OK == isZSLModeAvailable(staticMeta, YUV_REPROCESS)) {
+                ASSERT_TRUE(hasY8ToY8);
+                ASSERT_TRUE(hasY8ToBlob);
+            }
+        }
+
+        ndk::ScopedAStatus ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Check whether session parameters are supported. If Hal support for them
+// exist, then try to configure a preview stream using them.
+TEST_P(CameraAidlTest, configureStreamsWithSessionParameters) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::vector<AvailableStream> outputPreviewStreams;
+    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                        static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+
+    for (const auto& name : cameraDeviceNames) {
+        CameraMetadata meta;
+
+        std::shared_ptr<ICameraDevice> unusedCameraDevice;
+        openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+                               &unusedCameraDevice /*out*/);
+        camera_metadata_t* staticMetaBuffer =
+                reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
+
+        std::unordered_set<int32_t> availableSessionKeys;
+        auto rc = getSupportedKeys(staticMetaBuffer, ANDROID_REQUEST_AVAILABLE_SESSION_KEYS,
+                                   &availableSessionKeys);
+        ASSERT_TRUE(Status::OK == rc);
+        if (availableSessionKeys.empty()) {
+            ndk::ScopedAStatus ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        android::hardware::camera::common::V1_0::helper::CameraMetadata previewRequestSettings;
+        android::hardware::camera::common::V1_0::helper::CameraMetadata sessionParams,
+                modifiedSessionParams;
+        constructFilteredSettings(mSession, availableSessionKeys, RequestTemplate::PREVIEW,
+                                  &previewRequestSettings, &sessionParams);
+        if (sessionParams.isEmpty()) {
+            ndk::ScopedAStatus ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        outputPreviewStreams.clear();
+
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMetaBuffer, outputPreviewStreams,
+                                                        &previewThreshold));
+        ASSERT_NE(0u, outputPreviewStreams.size());
+
+        Stream previewStream = {
+                0,
+                StreamType::OUTPUT,
+                outputPreviewStreams[0].width,
+                outputPreviewStreams[0].height,
+                static_cast<PixelFormat>(outputPreviewStreams[0].format),
+                static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                        GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
+                Dataspace::UNKNOWN,
+                StreamRotation::ROTATION_0,
+                std::string(),
+                /*bufferSize*/ 0,
+                /*groupId*/ -1,
+                {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                RequestAvailableDynamicRangeProfilesMap::
+                        ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+
+        std::vector<Stream> streams = {previewStream};
+        StreamConfiguration config;
+
+        config.streams = streams;
+        config.operationMode = StreamConfigurationMode::NORMAL_MODE;
+        modifiedSessionParams = sessionParams;
+        auto sessionParamsBuffer = sessionParams.release();
+        std::vector<uint8_t> rawSessionParam =
+                std::vector(reinterpret_cast<uint8_t*>(sessionParamsBuffer),
+                            reinterpret_cast<uint8_t*>(sessionParamsBuffer) +
+                                    get_camera_metadata_size(sessionParamsBuffer));
+
+        config.sessionParams.metadata = rawSessionParam;
+        config.streamConfigCounter = 0;
+        config.streams = {previewStream};
+        config.streamConfigCounter = 0;
+        config.multiResolutionInputImage = false;
+
+        bool newSessionParamsAvailable = false;
+        for (const auto& it : availableSessionKeys) {
+            if (modifiedSessionParams.exists(it)) {
+                modifiedSessionParams.erase(it);
+                newSessionParamsAvailable = true;
+                break;
+            }
+        }
+        if (newSessionParamsAvailable) {
+            auto modifiedSessionParamsBuffer = modifiedSessionParams.release();
+            verifySessionReconfigurationQuery(mSession, sessionParamsBuffer,
+                                              modifiedSessionParamsBuffer);
+            modifiedSessionParams.acquire(modifiedSessionParamsBuffer);
+        }
+
+        std::vector<HalStream> halConfigs;
+        ndk::ScopedAStatus ret = mSession->configureStreams(config, &halConfigs);
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(1u, halConfigs.size());
+
+        sessionParams.acquire(sessionParamsBuffer);
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Verify that all supported preview + still capture stream combinations
+// can be configured successfully.
+TEST_P(CameraAidlTest, configureStreamsPreviewStillOutputs) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::vector<AvailableStream> outputBlobStreams;
+    std::vector<AvailableStream> outputPreviewStreams;
+    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                        static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+    AvailableStream blobThreshold = {INT32_MAX, INT32_MAX, static_cast<int32_t>(PixelFormat::BLOB)};
+
+    for (const auto& name : cameraDeviceNames) {
+        CameraMetadata meta;
+
+        std::shared_ptr<ICameraDevice> cameraDevice;
+        openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+                               &cameraDevice /*out*/);
+
+        camera_metadata_t* staticMeta = reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
+
+        // Check if camera support depth only
+        if (isDepthOnly(staticMeta)) {
+            ndk::ScopedAStatus ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        outputBlobStreams.clear();
+        ASSERT_EQ(Status::OK,
+                  getAvailableOutputStreams(staticMeta, outputBlobStreams, &blobThreshold));
+        ASSERT_NE(0u, outputBlobStreams.size());
+
+        outputPreviewStreams.clear();
+        ASSERT_EQ(Status::OK,
+                  getAvailableOutputStreams(staticMeta, outputPreviewStreams, &previewThreshold));
+        ASSERT_NE(0u, outputPreviewStreams.size());
+
+        int32_t jpegBufferSize = 0;
+        ASSERT_EQ(Status::OK, getJpegBufferSize(staticMeta, &jpegBufferSize));
+        ASSERT_NE(0u, jpegBufferSize);
+
+        int32_t streamId = 0;
+        uint32_t streamConfigCounter = 0;
+
+        for (auto& blobIter : outputBlobStreams) {
+            for (auto& previewIter : outputPreviewStreams) {
+                Stream previewStream = {
+                        streamId++,
+                        StreamType::OUTPUT,
+                        previewIter.width,
+                        previewIter.height,
+                        static_cast<PixelFormat>(previewIter.format),
+                        static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                                GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
+                        Dataspace::UNKNOWN,
+                        StreamRotation::ROTATION_0,
+                        std::string(),
+                        /*bufferSize*/ 0,
+                        /*groupId*/ -1,
+                        {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                        RequestAvailableDynamicRangeProfilesMap::
+                                ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+                Stream blobStream = {
+                        streamId++,
+                        StreamType::OUTPUT,
+                        blobIter.width,
+                        blobIter.height,
+                        static_cast<PixelFormat>(blobIter.format),
+                        static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                                GRALLOC1_CONSUMER_USAGE_CPU_READ),
+                        Dataspace::JFIF,
+                        StreamRotation::ROTATION_0,
+                        std::string(),
+                        /*bufferSize*/ 0,
+                        /*groupId*/ -1,
+                        {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                        RequestAvailableDynamicRangeProfilesMap::
+                                ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+                std::vector<Stream> streams = {previewStream, blobStream};
+                StreamConfiguration config;
+
+                createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
+                                          jpegBufferSize);
+                config.streamConfigCounter = streamConfigCounter++;
+                verifyStreamCombination(cameraDevice, config, /*expectedStatus*/ true,
+                                        /*expectStreamCombQuery*/ false);
+
+                std::vector<HalStream> halConfigs;
+                ndk::ScopedAStatus ret = mSession->configureStreams(config, &halConfigs);
+                ASSERT_TRUE(ret.isOk());
+                ASSERT_EQ(2u, halConfigs.size());
+            }
+        }
+
+        ndk::ScopedAStatus ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// In case constrained mode is supported, test whether it can be
+// configured. Additionally check for common invalid inputs when
+// using this mode.
+TEST_P(CameraAidlTest, configureStreamsConstrainedOutputs) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+
+    for (const auto& name : cameraDeviceNames) {
+        CameraMetadata meta;
+        std::shared_ptr<ICameraDevice> cameraDevice;
+
+        openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+                               &cameraDevice /*out*/);
+        camera_metadata_t* staticMeta = reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
+
+        Status rc = isConstrainedModeAvailable(staticMeta);
+        if (Status::OPERATION_NOT_SUPPORTED == rc) {
+            ndk::ScopedAStatus ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+        ASSERT_EQ(Status::OK, rc);
+
+        AvailableStream hfrStream;
+        rc = pickConstrainedModeSize(staticMeta, hfrStream);
+        ASSERT_EQ(Status::OK, rc);
+
+        int32_t streamId = 0;
+        uint32_t streamConfigCounter = 0;
+        Stream stream = {streamId,
+                         StreamType::OUTPUT,
+                         hfrStream.width,
+                         hfrStream.height,
+                         static_cast<PixelFormat>(hfrStream.format),
+                         static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                                 GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER),
+                         Dataspace::UNKNOWN,
+                         StreamRotation::ROTATION_0,
+                         std::string(),
+                         /*bufferSize*/ 0,
+                         /*groupId*/ -1,
+                         {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                         RequestAvailableDynamicRangeProfilesMap::
+                                 ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+        std::vector<Stream> streams = {stream};
+        StreamConfiguration config;
+        createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
+                                  &config);
+
+        verifyStreamCombination(cameraDevice, config, /*expectedStatus*/ true,
+                                /*expectStreamCombQuery*/ false);
+
+        config.streamConfigCounter = streamConfigCounter++;
+        std::vector<HalStream> halConfigs;
+        ndk::ScopedAStatus ret = mSession->configureStreams(config, &halConfigs);
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(1u, halConfigs.size());
+        ASSERT_EQ(halConfigs[0].id, streamId);
+
+        stream = {streamId++,
+                  StreamType::OUTPUT,
+                  static_cast<uint32_t>(0),
+                  static_cast<uint32_t>(0),
+                  static_cast<PixelFormat>(hfrStream.format),
+                  static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                          GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER),
+                  Dataspace::UNKNOWN,
+                  StreamRotation::ROTATION_0,
+                  std::string(),
+                  /*bufferSize*/ 0,
+                  /*groupId*/ -1,
+                  {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                  RequestAvailableDynamicRangeProfilesMap::
+                          ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+        streams[0] = stream;
+        createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
+                                  &config);
+
+        config.streamConfigCounter = streamConfigCounter++;
+        std::vector<HalStream> halConfig;
+        ret = mSession->configureStreams(config, &halConfig);
+        ASSERT_TRUE(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT) ==
+                            ret.getServiceSpecificError() ||
+                    static_cast<int32_t>(Status::INTERNAL_ERROR) == ret.getServiceSpecificError());
+
+        stream = {streamId++,
+                  StreamType::OUTPUT,
+                  INT32_MAX,
+                  INT32_MAX,
+                  static_cast<PixelFormat>(hfrStream.format),
+                  static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                          GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER),
+                  Dataspace::UNKNOWN,
+                  StreamRotation::ROTATION_0,
+                  std::string(),
+                  /*bufferSize*/ 0,
+                  /*groupId*/ -1,
+                  {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                  RequestAvailableDynamicRangeProfilesMap::
+                          ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+        streams[0] = stream;
+        createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
+                                  &config);
+
+        config.streamConfigCounter = streamConfigCounter++;
+        halConfigs.clear();
+        ret = mSession->configureStreams(config, &halConfigs);
+        ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT), ret.getServiceSpecificError());
+
+        stream = {streamId++,
+                  StreamType::OUTPUT,
+                  hfrStream.width,
+                  hfrStream.height,
+                  static_cast<PixelFormat>(UINT32_MAX),
+                  static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                          GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER),
+                  Dataspace::UNKNOWN,
+                  StreamRotation::ROTATION_0,
+                  std::string(),
+                  /*bufferSize*/ 0,
+                  /*groupId*/ -1,
+                  {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                  RequestAvailableDynamicRangeProfilesMap::
+                          ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+        streams[0] = stream;
+        createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
+                                  &config);
+
+        config.streamConfigCounter = streamConfigCounter++;
+        halConfigs.clear();
+        ret = mSession->configureStreams(config, &halConfigs);
+        ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT), ret.getServiceSpecificError());
+
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Verify that all supported video + snapshot stream combinations can
+// be configured successfully.
+TEST_P(CameraAidlTest, configureStreamsVideoStillOutputs) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::vector<AvailableStream> outputBlobStreams;
+    std::vector<AvailableStream> outputVideoStreams;
+    AvailableStream videoThreshold = {kMaxVideoWidth, kMaxVideoHeight,
+                                      static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+    AvailableStream blobThreshold = {kMaxVideoWidth, kMaxVideoHeight,
+                                     static_cast<int32_t>(PixelFormat::BLOB)};
+
+    for (const auto& name : cameraDeviceNames) {
+        CameraMetadata meta;
+        std::shared_ptr<ICameraDevice> cameraDevice;
+
+        openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+                               &cameraDevice /*out*/);
+
+        camera_metadata_t* staticMeta = reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
+
+        // Check if camera support depth only
+        if (isDepthOnly(staticMeta)) {
+            ndk::ScopedAStatus ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        outputBlobStreams.clear();
+        ASSERT_EQ(Status::OK,
+                  getAvailableOutputStreams(staticMeta, outputBlobStreams, &blobThreshold));
+        ASSERT_NE(0u, outputBlobStreams.size());
+
+        outputVideoStreams.clear();
+        ASSERT_EQ(Status::OK,
+                  getAvailableOutputStreams(staticMeta, outputVideoStreams, &videoThreshold));
+        ASSERT_NE(0u, outputVideoStreams.size());
+
+        int32_t jpegBufferSize = 0;
+        ASSERT_EQ(Status::OK, getJpegBufferSize(staticMeta, &jpegBufferSize));
+        ASSERT_NE(0u, jpegBufferSize);
+
+        int32_t streamId = 0;
+        uint32_t streamConfigCounter = 0;
+        for (auto& blobIter : outputBlobStreams) {
+            for (auto& videoIter : outputVideoStreams) {
+                Stream videoStream = {
+                        streamId++,
+                        StreamType::OUTPUT,
+                        videoIter.width,
+                        videoIter.height,
+                        static_cast<PixelFormat>(videoIter.format),
+                        static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                                GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER),
+                        Dataspace::UNKNOWN,
+                        StreamRotation::ROTATION_0,
+                        std::string(),
+                        jpegBufferSize,
+                        /*groupId*/ -1,
+                        {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                        RequestAvailableDynamicRangeProfilesMap::
+                                ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+                Stream blobStream = {
+                        streamId++,
+                        StreamType::OUTPUT,
+                        blobIter.width,
+                        blobIter.height,
+                        static_cast<PixelFormat>(blobIter.format),
+                        static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                                GRALLOC1_CONSUMER_USAGE_CPU_READ),
+                        Dataspace::JFIF,
+                        StreamRotation::ROTATION_0,
+                        std::string(),
+                        jpegBufferSize,
+                        /*groupId*/ -1,
+                        {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                        RequestAvailableDynamicRangeProfilesMap::
+                                ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+                std::vector<Stream> streams = {videoStream, blobStream};
+                StreamConfiguration config;
+
+                createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
+                                          jpegBufferSize);
+                verifyStreamCombination(cameraDevice, config, /*expectedStatus*/ true,
+                                        /*expectStreamCombQuery*/ false);
+
+                config.streamConfigCounter = streamConfigCounter++;
+                std::vector<HalStream> halConfigs;
+                ndk::ScopedAStatus ret = mSession->configureStreams(config, &halConfigs);
+                ASSERT_TRUE(ret.isOk());
+                ASSERT_EQ(2u, halConfigs.size());
+            }
+        }
+
+        ndk::ScopedAStatus ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Generate and verify a camera capture request
+TEST_P(CameraAidlTest, processCaptureRequestPreview) {
+    // TODO(b/220897574): Failing with BUFFER_ERROR
+    processCaptureRequestInternal(GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, RequestTemplate::PREVIEW,
+                                  false /*secureOnlyCameras*/);
+}
+
+// Generate and verify a secure camera capture request
+TEST_P(CameraAidlTest, processSecureCaptureRequest) {
+    processCaptureRequestInternal(GRALLOC1_PRODUCER_USAGE_PROTECTED, RequestTemplate::STILL_CAPTURE,
+                                  true /*secureOnlyCameras*/);
+}
+
+TEST_P(CameraAidlTest, processCaptureRequestPreviewStabilization) {
+    std::unordered_map<std::string, nsecs_t> cameraDeviceToTimeLag;
+    processPreviewStabilizationCaptureRequestInternal(/*previewStabilizationOn*/ false,
+                                                      cameraDeviceToTimeLag);
+    processPreviewStabilizationCaptureRequestInternal(/*previewStabilizationOn*/ true,
+                                                      cameraDeviceToTimeLag);
+}
+
+// Generate and verify a multi-camera capture request
+TEST_P(CameraAidlTest, processMultiCaptureRequestPreview) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                        static_cast<int32_t>(PixelFormat::YCBCR_420_888)};
+    int64_t bufferId = 1;
+    uint32_t frameNumber = 1;
+    std::vector<uint8_t> settings;
+    std::vector<uint8_t> emptySettings;
+    std::string invalidPhysicalId = "-1";
+
+    for (const auto& name : cameraDeviceNames) {
+        std::string version, deviceId;
+        ALOGI("processMultiCaptureRequestPreview: Test device %s", name.c_str());
+        ASSERT_TRUE(matchDeviceName(name, mProviderType, &version, &deviceId));
+        CameraMetadata metadata;
+
+        std::shared_ptr<ICameraDevice> unusedDevice;
+        openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &metadata /*out*/,
+                               &unusedDevice /*out*/);
+
+        camera_metadata_t* staticMeta =
+                reinterpret_cast<camera_metadata_t*>(metadata.metadata.data());
+        Status rc = isLogicalMultiCamera(staticMeta);
+        if (Status::OPERATION_NOT_SUPPORTED == rc) {
+            ndk::ScopedAStatus ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+        ASSERT_EQ(Status::OK, rc);
+
+        std::unordered_set<std::string> physicalIds;
+        rc = getPhysicalCameraIds(staticMeta, &physicalIds);
+        ASSERT_TRUE(Status::OK == rc);
+        ASSERT_TRUE(physicalIds.size() > 1);
+
+        std::unordered_set<int32_t> physicalRequestKeyIDs;
+        rc = getSupportedKeys(staticMeta, ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS,
+                              &physicalRequestKeyIDs);
+        ASSERT_TRUE(Status::OK == rc);
+        if (physicalRequestKeyIDs.empty()) {
+            ndk::ScopedAStatus ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            // The logical camera doesn't support any individual physical requests.
+            continue;
+        }
+
+        android::hardware::camera::common::V1_0::helper::CameraMetadata defaultPreviewSettings;
+        android::hardware::camera::common::V1_0::helper::CameraMetadata filteredSettings;
+        constructFilteredSettings(mSession, physicalRequestKeyIDs, RequestTemplate::PREVIEW,
+                                  &defaultPreviewSettings, &filteredSettings);
+        if (filteredSettings.isEmpty()) {
+            // No physical device settings in default request.
+            ndk::ScopedAStatus ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        const camera_metadata_t* settingsBuffer = defaultPreviewSettings.getAndLock();
+        uint8_t* rawSettingsBuffer = (uint8_t*)settingsBuffer;
+        settings.assign(rawSettingsBuffer,
+                        rawSettingsBuffer + get_camera_metadata_size(settingsBuffer));
+        CameraMetadata settingsMetadata = {settings};
+        overrideRotateAndCrop(&settingsMetadata);
+
+        ndk::ScopedAStatus ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+
+        // Leave only 2 physical devices in the id set.
+        auto it = physicalIds.begin();
+        std::string physicalDeviceId = *it;
+        it++;
+        physicalIds.erase(++it, physicalIds.end());
+        ASSERT_EQ(physicalIds.size(), 2u);
+
+        std::vector<HalStream> halStreams;
+        bool supportsPartialResults = false;
+        bool useHalBufManager = false;
+        int32_t partialResultCount = 0;
+        Stream previewStream;
+        std::shared_ptr<DeviceCb> cb;
+
+        configurePreviewStreams(
+                name, mProvider, &previewThreshold, physicalIds, &mSession, &previewStream,
+                &halStreams /*out*/, &supportsPartialResults /*out*/, &partialResultCount /*out*/,
+                &useHalBufManager /*out*/, &cb /*out*/, 0 /*streamConfigCounter*/, true);
+        if (mSession == nullptr) {
+            // stream combination not supported by HAL, skip test for device
+            continue;
+        }
+
+        ::aidl::android::hardware::common::fmq::MQDescriptor<
+                int8_t, aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+                descriptor;
+        auto resultQueueRet = mSession->getCaptureResultMetadataQueue(&descriptor);
+        ASSERT_TRUE(resultQueueRet.isOk());
+        std::shared_ptr<ResultMetadataQueue> resultQueue =
+                std::make_shared<ResultMetadataQueue>(descriptor);
+        if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
+            ALOGE("%s: HAL returns empty result metadata fmq, not use it", __func__);
+            resultQueue = nullptr;
+            // Don't use the queue onwards.
+        }
+
+        std::shared_ptr<InFlightRequest> inflightReq = std::make_shared<InFlightRequest>(
+                static_cast<ssize_t>(halStreams.size()), false, supportsPartialResults,
+                partialResultCount, physicalIds, resultQueue);
+
+        std::vector<CaptureRequest> requests(1);
+        CaptureRequest& request = requests[0];
+        request.frameNumber = frameNumber;
+        request.fmqSettingsSize = 0;
+        request.settings.metadata = settings;
+
+        std::vector<StreamBuffer>& outputBuffers = request.outputBuffers;
+
+        std::vector<buffer_handle_t> graphicBuffers;
+        graphicBuffers.reserve(halStreams.size());
+        outputBuffers.resize(halStreams.size());
+        size_t k = 0;
+        for (const auto& halStream : halStreams) {
+            buffer_handle_t buffer_handle;
+            if (useHalBufManager) {
+                outputBuffers[k] = {halStream.id,     /*bufferId*/ 0, NativeHandle(),
+                                    BufferStatus::OK, NativeHandle(), NativeHandle()};
+            } else {
+                allocateGraphicBuffer(previewStream.width, previewStream.height,
+                                      android_convertGralloc1To0Usage(
+                                              static_cast<uint64_t>(halStream.producerUsage),
+                                              static_cast<uint64_t>(halStream.consumerUsage)),
+                                      halStream.overrideFormat, &buffer_handle);
+                graphicBuffers.push_back(buffer_handle);
+                outputBuffers[k] = {
+                        halStream.id,     bufferId,       ::android::makeToAidl(buffer_handle),
+                        BufferStatus::OK, NativeHandle(), NativeHandle()};
+                bufferId++;
+            }
+            k++;
+        }
+
+        std::vector<PhysicalCameraSetting> camSettings(1);
+        const camera_metadata_t* filteredSettingsBuffer = filteredSettings.getAndLock();
+        uint8_t* rawFilteredSettingsBuffer = (uint8_t*)filteredSettingsBuffer;
+        camSettings[0].settings = {std::vector(
+                rawFilteredSettingsBuffer,
+                rawFilteredSettingsBuffer + get_camera_metadata_size(filteredSettingsBuffer))};
+        overrideRotateAndCrop(&camSettings[0].settings);
+        camSettings[0].fmqSettingsSize = 0;
+        camSettings[0].physicalCameraId = physicalDeviceId;
+
+        request.inputBuffer = {
+                -1, 0, NativeHandle(), BufferStatus::ERROR, NativeHandle(), NativeHandle()};
+        request.physicalCameraSettings = camSettings;
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            mInflightMap.clear();
+            mInflightMap[frameNumber] = inflightReq;
+        }
+
+        int32_t numRequestProcessed = 0;
+        std::vector<BufferCache> cachesToRemove;
+        ndk::ScopedAStatus returnStatus =
+                mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(numRequestProcessed, 1u);
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReq->errorCodeValid &&
+                   ((0 < inflightReq->numBuffersLeft) || (!inflightReq->haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                               std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+            }
+
+            ASSERT_FALSE(inflightReq->errorCodeValid);
+            ASSERT_NE(inflightReq->resultOutputBuffers.size(), 0u);
+
+            request.frameNumber++;
+            // Empty settings should be supported after the first call
+            // for repeating requests.
+            request.settings.metadata.clear();
+            request.physicalCameraSettings[0].settings.metadata.clear();
+            // The buffer has been registered to HAL by bufferId, so per
+            // API contract we should send a null handle for this buffer
+            request.outputBuffers[0].buffer = NativeHandle();
+            mInflightMap.clear();
+            inflightReq = std::make_shared<InFlightRequest>(
+                    static_cast<ssize_t>(physicalIds.size()), false, supportsPartialResults,
+                    partialResultCount, physicalIds, resultQueue);
+            mInflightMap[request.frameNumber] = inflightReq;
+        }
+
+        returnStatus =
+                mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(numRequestProcessed, 1u);
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReq->errorCodeValid &&
+                   ((0 < inflightReq->numBuffersLeft) || (!inflightReq->haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                               std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+            }
+
+            ASSERT_FALSE(inflightReq->errorCodeValid);
+            ASSERT_NE(inflightReq->resultOutputBuffers.size(), 0u);
+        }
+
+        // Invalid physical camera id should fail process requests
+        frameNumber++;
+        camSettings[0].physicalCameraId = invalidPhysicalId;
+        camSettings[0].settings.metadata = settings;
+
+        request.physicalCameraSettings = camSettings;  // Invalid camera settings
+        returnStatus =
+                mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+        ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT),
+                  returnStatus.getServiceSpecificError());
+
+        defaultPreviewSettings.unlock(settingsBuffer);
+        filteredSettings.unlock(filteredSettingsBuffer);
+
+        if (useHalBufManager) {
+            std::vector<int32_t> streamIds(halStreams.size());
+            for (size_t i = 0; i < streamIds.size(); i++) {
+                streamIds[i] = halStreams[i].id;
+            }
+            verifyBuffersReturned(mSession, streamIds, cb);
+        }
+
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Generate and verify an ultra high resolution capture request
+TEST_P(CameraAidlTest, processUltraHighResolutionRequest) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    int64_t bufferId = 1;
+    int32_t frameNumber = 1;
+    CameraMetadata settings;
+
+    for (const auto& name : cameraDeviceNames) {
+        std::string version, deviceId;
+        ASSERT_TRUE(matchDeviceName(name, mProviderType, &version, &deviceId));
+        CameraMetadata meta;
+
+        std::shared_ptr<ICameraDevice> unusedDevice;
+        openEmptyDeviceSession(name, mProvider, &mSession, &meta, &unusedDevice);
+        camera_metadata_t* staticMeta = reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
+        if (!isUltraHighResolution(staticMeta)) {
+            ndk::ScopedAStatus ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+        CameraMetadata req;
+        android::hardware::camera::common::V1_0::helper::CameraMetadata defaultSettings;
+        ndk::ScopedAStatus ret =
+                mSession->constructDefaultRequestSettings(RequestTemplate::STILL_CAPTURE, &req);
+        ASSERT_TRUE(ret.isOk());
+
+        const camera_metadata_t* metadata =
+                reinterpret_cast<const camera_metadata_t*>(req.metadata.data());
+        size_t expectedSize = req.metadata.size();
+        int result = validate_camera_metadata_structure(metadata, &expectedSize);
+        ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+
+        size_t entryCount = get_camera_metadata_entry_count(metadata);
+        ASSERT_GT(entryCount, 0u);
+        defaultSettings = metadata;
+        uint8_t sensorPixelMode =
+                static_cast<uint8_t>(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION);
+        ASSERT_EQ(::android::OK,
+                  defaultSettings.update(ANDROID_SENSOR_PIXEL_MODE, &sensorPixelMode, 1));
+
+        const camera_metadata_t* settingsBuffer = defaultSettings.getAndLock();
+        uint8_t* rawSettingsBuffer = (uint8_t*)settingsBuffer;
+        settings.metadata = std::vector(
+                rawSettingsBuffer, rawSettingsBuffer + get_camera_metadata_size(settingsBuffer));
+        overrideRotateAndCrop(&settings);
+
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+
+        std::vector<HalStream> halStreams;
+        bool supportsPartialResults = false;
+        bool useHalBufManager = false;
+        int32_t partialResultCount = 0;
+        Stream previewStream;
+        std::shared_ptr<DeviceCb> cb;
+
+        std::list<PixelFormat> pixelFormats = {PixelFormat::YCBCR_420_888, PixelFormat::RAW16};
+        for (PixelFormat format : pixelFormats) {
+            configureStreams(name, mProvider, format, &mSession, &previewStream, &halStreams,
+                             &supportsPartialResults, &partialResultCount, &useHalBufManager, &cb,
+                             0, /*maxResolution*/ true);
+            ASSERT_NE(mSession, nullptr);
+
+            ::aidl::android::hardware::common::fmq::MQDescriptor<
+                    int8_t, aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+                    descriptor;
+            auto resultQueueRet = mSession->getCaptureResultMetadataQueue(&descriptor);
+            ASSERT_TRUE(resultQueueRet.isOk());
+
+            std::shared_ptr<ResultMetadataQueue> resultQueue =
+                    std::make_shared<ResultMetadataQueue>(descriptor);
+            if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
+                ALOGE("%s: HAL returns empty result metadata fmq, not use it", __func__);
+                resultQueue = nullptr;
+                // Don't use the queue onwards.
+            }
+
+            std::vector<buffer_handle_t> graphicBuffers;
+            graphicBuffers.reserve(halStreams.size());
+            std::shared_ptr<InFlightRequest> inflightReq = std::make_shared<InFlightRequest>(
+                    static_cast<ssize_t>(halStreams.size()), false, supportsPartialResults,
+                    partialResultCount, std::unordered_set<std::string>(), resultQueue);
+
+            std::vector<CaptureRequest> requests(1);
+            CaptureRequest& request = requests[0];
+            std::vector<StreamBuffer>& outputBuffers = request.outputBuffers;
+            outputBuffers.resize(halStreams.size());
+
+            size_t k = 0;
+            for (const auto& halStream : halStreams) {
+                buffer_handle_t buffer_handle;
+                if (useHalBufManager) {
+                    outputBuffers[k] = {halStream.id,   0,
+                                        NativeHandle(), BufferStatus::OK,
+                                        NativeHandle(), NativeHandle()};
+                } else {
+                    allocateGraphicBuffer(previewStream.width, previewStream.height,
+                                          android_convertGralloc1To0Usage(
+                                                  static_cast<uint64_t>(halStream.producerUsage),
+                                                  static_cast<uint64_t>(halStream.consumerUsage)),
+                                          halStream.overrideFormat, &buffer_handle);
+                    graphicBuffers.push_back(buffer_handle);
+                    outputBuffers[k] = {
+                            halStream.id,     bufferId,       ::android::makeToAidl(buffer_handle),
+                            BufferStatus::OK, NativeHandle(), NativeHandle()};
+                    bufferId++;
+                }
+                k++;
+            }
+
+            request.inputBuffer = {
+                    -1, 0, NativeHandle(), BufferStatus::ERROR, NativeHandle(), NativeHandle()};
+            request.frameNumber = frameNumber;
+            request.fmqSettingsSize = 0;
+            request.settings = settings;
+            request.inputWidth = 0;
+            request.inputHeight = 0;
+
+            {
+                std::unique_lock<std::mutex> l(mLock);
+                mInflightMap.clear();
+                mInflightMap[frameNumber] = inflightReq;
+            }
+
+            int32_t numRequestProcessed = 0;
+            std::vector<BufferCache> cachesToRemove;
+            ndk::ScopedAStatus returnStatus =
+                    mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+            ASSERT_TRUE(returnStatus.isOk());
+            ASSERT_EQ(numRequestProcessed, 1u);
+
+            {
+                std::unique_lock<std::mutex> l(mLock);
+                while (!inflightReq->errorCodeValid &&
+                       ((0 < inflightReq->numBuffersLeft) || (!inflightReq->haveResultMetadata))) {
+                    auto timeout = std::chrono::system_clock::now() +
+                                   std::chrono::seconds(kStreamBufferTimeoutSec);
+                    ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+                }
+
+                ASSERT_FALSE(inflightReq->errorCodeValid);
+                ASSERT_NE(inflightReq->resultOutputBuffers.size(), 0u);
+            }
+            if (useHalBufManager) {
+                std::vector<int32_t> streamIds(halStreams.size());
+                for (size_t i = 0; i < streamIds.size(); i++) {
+                    streamIds[i] = halStreams[i].id;
+                }
+                verifyBuffersReturned(mSession, streamIds, cb);
+            }
+
+            ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+        }
+    }
+}
+
+// Generate and verify 10-bit dynamic range request
+TEST_P(CameraAidlTest, process10BitDynamicRangeRequest) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    int64_t bufferId = 1;
+    int32_t frameNumber = 1;
+    CameraMetadata settings;
+
+    for (const auto& name : cameraDeviceNames) {
+        std::string version, deviceId;
+        ASSERT_TRUE(matchDeviceName(name, mProviderType, &version, &deviceId));
+        CameraMetadata meta;
+        std::shared_ptr<ICameraDevice> device;
+        openEmptyDeviceSession(name, mProvider, &mSession, &meta, &device);
+        camera_metadata_t* staticMeta = reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
+        if (!is10BitDynamicRangeCapable(staticMeta)) {
+            ndk::ScopedAStatus ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+        std::vector<RequestAvailableDynamicRangeProfilesMap> profileList;
+        get10BitDynamicRangeProfiles(staticMeta, &profileList);
+        ASSERT_FALSE(profileList.empty());
+
+        CameraMetadata req;
+        android::hardware::camera::common::V1_0::helper::CameraMetadata defaultSettings;
+        ndk::ScopedAStatus ret =
+                mSession->constructDefaultRequestSettings(RequestTemplate::STILL_CAPTURE, &req);
+        ASSERT_TRUE(ret.isOk());
+
+        const camera_metadata_t* metadata =
+                reinterpret_cast<const camera_metadata_t*>(req.metadata.data());
+        size_t expectedSize = req.metadata.size();
+        int result = validate_camera_metadata_structure(metadata, &expectedSize);
+        ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+
+        size_t entryCount = get_camera_metadata_entry_count(metadata);
+        ASSERT_GT(entryCount, 0u);
+        defaultSettings = metadata;
+
+        const camera_metadata_t* settingsBuffer = defaultSettings.getAndLock();
+        uint8_t* rawSettingsBuffer = (uint8_t*)settingsBuffer;
+        settings.metadata = std::vector(
+                rawSettingsBuffer, rawSettingsBuffer + get_camera_metadata_size(settingsBuffer));
+        overrideRotateAndCrop(&settings);
+
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+
+        std::vector<HalStream> halStreams;
+        bool supportsPartialResults = false;
+        bool useHalBufManager = false;
+        int32_t partialResultCount = 0;
+        Stream previewStream;
+        std::shared_ptr<DeviceCb> cb;
+        for (const auto& profile : profileList) {
+            configureStreams(name, mProvider, PixelFormat::IMPLEMENTATION_DEFINED, &mSession,
+                             &previewStream, &halStreams, &supportsPartialResults,
+                             &partialResultCount, &useHalBufManager, &cb, 0,
+                             /*maxResolution*/ false, profile);
+            ASSERT_NE(mSession, nullptr);
+
+            ::aidl::android::hardware::common::fmq::MQDescriptor<
+                    int8_t, aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+                    descriptor;
+            auto resultQueueRet = mSession->getCaptureResultMetadataQueue(&descriptor);
+            ASSERT_TRUE(resultQueueRet.isOk());
+
+            std::shared_ptr<ResultMetadataQueue> resultQueue =
+                    std::make_shared<ResultMetadataQueue>(descriptor);
+            if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
+                ALOGE("%s: HAL returns empty result metadata fmq, not use it", __func__);
+                resultQueue = nullptr;
+                // Don't use the queue onwards.
+            }
+
+            std::vector<buffer_handle_t> graphicBuffers;
+            graphicBuffers.reserve(halStreams.size());
+
+            std::shared_ptr<InFlightRequest> inflightReq = std::make_shared<InFlightRequest>(
+                    static_cast<ssize_t>(halStreams.size()), false, supportsPartialResults,
+                    partialResultCount, std::unordered_set<std::string>(), resultQueue);
+
+            std::vector<CaptureRequest> requests(1);
+            CaptureRequest& request = requests[0];
+            std::vector<StreamBuffer>& outputBuffers = request.outputBuffers;
+            outputBuffers.resize(halStreams.size());
+
+            size_t k = 0;
+            for (const auto& halStream : halStreams) {
+                buffer_handle_t buffer_handle;
+                if (useHalBufManager) {
+                    outputBuffers[k] = {halStream.id,   0,
+                                        NativeHandle(), BufferStatus::OK,
+                                        NativeHandle(), NativeHandle()};
+                } else {
+                    allocateGraphicBuffer(previewStream.width, previewStream.height,
+                                          android_convertGralloc1To0Usage(
+                                                  static_cast<uint64_t>(halStream.producerUsage),
+                                                  static_cast<uint64_t>(halStream.consumerUsage)),
+                                          halStream.overrideFormat, &buffer_handle);
+
+                    graphicBuffers.push_back(buffer_handle);
+                    outputBuffers[k] = {
+                            halStream.id,     bufferId,       android::makeToAidl(buffer_handle),
+                            BufferStatus::OK, NativeHandle(), NativeHandle()};
+                    bufferId++;
+                }
+                k++;
+            }
+
+            request.inputBuffer = {
+                    -1, 0, NativeHandle(), BufferStatus::ERROR, NativeHandle(), NativeHandle()};
+            request.frameNumber = frameNumber;
+            request.fmqSettingsSize = 0;
+            request.settings = settings;
+            request.inputWidth = 0;
+            request.inputHeight = 0;
+
+            {
+                std::unique_lock<std::mutex> l(mLock);
+                mInflightMap.clear();
+                mInflightMap[frameNumber] = inflightReq;
+            }
+
+            int32_t numRequestProcessed = 0;
+            std::vector<BufferCache> cachesToRemove;
+            ndk::ScopedAStatus returnStatus =
+                    mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+            ASSERT_TRUE(returnStatus.isOk());
+            ASSERT_EQ(numRequestProcessed, 1u);
+
+            {
+                std::unique_lock<std::mutex> l(mLock);
+                while (!inflightReq->errorCodeValid &&
+                       ((0 < inflightReq->numBuffersLeft) || (!inflightReq->haveResultMetadata))) {
+                    auto timeout = std::chrono::system_clock::now() +
+                                   std::chrono::seconds(kStreamBufferTimeoutSec);
+                    ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+                }
+
+                ASSERT_FALSE(inflightReq->errorCodeValid);
+                ASSERT_NE(inflightReq->resultOutputBuffers.size(), 0u);
+                verify10BitMetadata(mHandleImporter, *inflightReq, profile);
+            }
+            if (useHalBufManager) {
+                std::vector<int32_t> streamIds(halStreams.size());
+                for (size_t i = 0; i < streamIds.size(); i++) {
+                    streamIds[i] = halStreams[i].id;
+                }
+                mSession->signalStreamFlush(streamIds, /*streamConfigCounter*/ 0);
+                cb->waitForBuffersReturned();
+            }
+
+            ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+        }
+    }
+}
+
+// Generate and verify a burst containing alternating sensor sensitivity values
+TEST_P(CameraAidlTest, processCaptureRequestBurstISO) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                        static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+    int64_t bufferId = 1;
+    int32_t frameNumber = 1;
+    float isoTol = .03f;
+    CameraMetadata settings;
+
+    for (const auto& name : cameraDeviceNames) {
+        CameraMetadata meta;
+        settings.metadata.clear();
+        std::shared_ptr<ICameraDevice> unusedDevice;
+        openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+                               &unusedDevice /*out*/);
+        camera_metadata_t* staticMetaBuffer =
+                clone_camera_metadata(reinterpret_cast<camera_metadata_t*>(meta.metadata.data()));
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata staticMeta(
+                staticMetaBuffer);
+
+        camera_metadata_entry_t hwLevel = staticMeta.find(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL);
+        ASSERT_TRUE(0 < hwLevel.count);
+        if (ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED == hwLevel.data.u8[0] ||
+            ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL == hwLevel.data.u8[0]) {
+            // Limited/External devices can skip this test
+            ndk::ScopedAStatus ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        camera_metadata_entry_t isoRange = staticMeta.find(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE);
+        ASSERT_EQ(isoRange.count, 2u);
+
+        ndk::ScopedAStatus ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+
+        bool supportsPartialResults = false;
+        bool useHalBufManager = false;
+        int32_t partialResultCount = 0;
+        Stream previewStream;
+        std::vector<HalStream> halStreams;
+        std::shared_ptr<DeviceCb> cb;
+        configurePreviewStream(name, mProvider, &previewThreshold, &mSession /*out*/,
+                               &previewStream /*out*/, &halStreams /*out*/,
+                               &supportsPartialResults /*out*/, &partialResultCount /*out*/,
+                               &useHalBufManager /*out*/, &cb /*out*/);
+
+        ::aidl::android::hardware::common::fmq::MQDescriptor<
+                int8_t, aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+                descriptor;
+        auto resultQueueRet = mSession->getCaptureResultMetadataQueue(&descriptor);
+        std::shared_ptr<ResultMetadataQueue> resultQueue =
+                std::make_shared<ResultMetadataQueue>(descriptor);
+        ASSERT_TRUE(resultQueueRet.isOk());
+        if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
+            ALOGE("%s: HAL returns empty result metadata fmq, not use it", __func__);
+            resultQueue = nullptr;
+            // Don't use the queue onwards.
+        }
+
+        ret = mSession->constructDefaultRequestSettings(RequestTemplate::PREVIEW, &settings);
+        ASSERT_TRUE(ret.isOk());
+
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata requestMeta;
+        std::vector<CaptureRequest> requests(kBurstFrameCount);
+        std::vector<buffer_handle_t> buffers(kBurstFrameCount);
+        std::vector<std::shared_ptr<InFlightRequest>> inflightReqs(kBurstFrameCount);
+        std::vector<int32_t> isoValues(kBurstFrameCount);
+        std::vector<CameraMetadata> requestSettings(kBurstFrameCount);
+
+        for (int32_t i = 0; i < kBurstFrameCount; i++) {
+            std::unique_lock<std::mutex> l(mLock);
+            CaptureRequest& request = requests[i];
+            std::vector<StreamBuffer>& outputBuffers = request.outputBuffers;
+            outputBuffers.resize(1);
+            StreamBuffer& outputBuffer = outputBuffers[0];
+
+            isoValues[i] = ((i % 2) == 0) ? isoRange.data.i32[0] : isoRange.data.i32[1];
+            if (useHalBufManager) {
+                outputBuffer = {halStreams[0].id, 0,
+                                NativeHandle(),   BufferStatus::OK,
+                                NativeHandle(),   NativeHandle()};
+            } else {
+                allocateGraphicBuffer(previewStream.width, previewStream.height,
+                                      android_convertGralloc1To0Usage(
+                                              static_cast<uint64_t>(halStreams[0].producerUsage),
+                                              static_cast<uint64_t>(halStreams[0].consumerUsage)),
+                                      halStreams[0].overrideFormat, &buffers[i]);
+                outputBuffer = {halStreams[0].id, bufferId + i,   ::android::makeToAidl(buffers[i]),
+                                BufferStatus::OK, NativeHandle(), NativeHandle()};
+            }
+
+            requestMeta.append(reinterpret_cast<camera_metadata_t*>(settings.metadata.data()));
+
+            // Disable all 3A routines
+            uint8_t mode = static_cast<uint8_t>(ANDROID_CONTROL_MODE_OFF);
+            ASSERT_EQ(::android::OK, requestMeta.update(ANDROID_CONTROL_MODE, &mode, 1));
+            ASSERT_EQ(::android::OK,
+                      requestMeta.update(ANDROID_SENSOR_SENSITIVITY, &isoValues[i], 1));
+            camera_metadata_t* metaBuffer = requestMeta.release();
+            uint8_t* rawMetaBuffer = reinterpret_cast<uint8_t*>(metaBuffer);
+            requestSettings[i].metadata = std::vector(
+                    rawMetaBuffer, rawMetaBuffer + get_camera_metadata_size(metaBuffer));
+            overrideRotateAndCrop(&(requestSettings[i]));
+
+            request.frameNumber = frameNumber + i;
+            request.fmqSettingsSize = 0;
+            request.settings = requestSettings[i];
+            request.inputBuffer = {
+                    -1, 0, NativeHandle(), BufferStatus::ERROR, NativeHandle(), NativeHandle()};
+
+            inflightReqs[i] = std::make_shared<InFlightRequest>(1, false, supportsPartialResults,
+                                                                partialResultCount, resultQueue);
+            mInflightMap[frameNumber + i] = inflightReqs[i];
+        }
+
+        int32_t numRequestProcessed = 0;
+        std::vector<BufferCache> cachesToRemove;
+
+        ndk::ScopedAStatus returnStatus =
+                mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(numRequestProcessed, kBurstFrameCount);
+
+        for (size_t i = 0; i < kBurstFrameCount; i++) {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReqs[i]->errorCodeValid && ((0 < inflightReqs[i]->numBuffersLeft) ||
+                                                        (!inflightReqs[i]->haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                               std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+            }
+
+            ASSERT_FALSE(inflightReqs[i]->errorCodeValid);
+            ASSERT_NE(inflightReqs[i]->resultOutputBuffers.size(), 0u);
+            ASSERT_EQ(previewStream.id, inflightReqs[i]->resultOutputBuffers[0].buffer.streamId);
+            ASSERT_FALSE(inflightReqs[i]->collectedResult.isEmpty());
+            ASSERT_TRUE(inflightReqs[i]->collectedResult.exists(ANDROID_SENSOR_SENSITIVITY));
+            camera_metadata_entry_t isoResult =
+                    inflightReqs[i]->collectedResult.find(ANDROID_SENSOR_SENSITIVITY);
+            ASSERT_TRUE(std::abs(isoResult.data.i32[0] - isoValues[i]) <=
+                        std::round(isoValues[i] * isoTol));
+        }
+
+        if (useHalBufManager) {
+            verifyBuffersReturned(mSession, previewStream.id, cb);
+        }
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Test whether an incorrect capture request with missing settings will
+// be reported correctly.
+TEST_P(CameraAidlTest, processCaptureRequestInvalidSinglePreview) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::vector<AvailableStream> outputPreviewStreams;
+    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                        static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+    int64_t bufferId = 1;
+    int32_t frameNumber = 1;
+    CameraMetadata settings;
+
+    for (const auto& name : cameraDeviceNames) {
+        Stream previewStream;
+        std::vector<HalStream> halStreams;
+        std::shared_ptr<DeviceCb> cb;
+        bool supportsPartialResults = false;
+        bool useHalBufManager = false;
+        int32_t partialResultCount = 0;
+        configurePreviewStream(name, mProvider, &previewThreshold, &mSession /*out*/,
+                               &previewStream /*out*/, &halStreams /*out*/,
+                               &supportsPartialResults /*out*/, &partialResultCount /*out*/,
+                               &useHalBufManager /*out*/, &cb /*out*/);
+        ASSERT_NE(mSession, nullptr);
+        ASSERT_FALSE(halStreams.empty());
+
+        buffer_handle_t buffer_handle = nullptr;
+
+        if (useHalBufManager) {
+            bufferId = 0;
+        } else {
+            allocateGraphicBuffer(previewStream.width, previewStream.height,
+                                  android_convertGralloc1To0Usage(
+                                          static_cast<uint64_t>(halStreams[0].producerUsage),
+                                          static_cast<uint64_t>(halStreams[0].consumerUsage)),
+                                  halStreams[0].overrideFormat, &buffer_handle);
+        }
+
+        std::vector<CaptureRequest> requests(1);
+        CaptureRequest& request = requests[0];
+        std::vector<StreamBuffer>& outputBuffers = request.outputBuffers;
+        outputBuffers.resize(1);
+        StreamBuffer& outputBuffer = outputBuffers[0];
+
+        outputBuffer = {
+                halStreams[0].id,
+                bufferId,
+                buffer_handle == nullptr ? NativeHandle() : ::android::makeToAidl(buffer_handle),
+                BufferStatus::OK,
+                NativeHandle(),
+                NativeHandle()};
+
+        request.inputBuffer = {
+                -1, 0, NativeHandle(), BufferStatus::ERROR, NativeHandle(), NativeHandle()};
+        request.frameNumber = frameNumber;
+        request.fmqSettingsSize = 0;
+        request.settings = settings;
+
+        // Settings were not correctly initialized, we should fail here
+        int32_t numRequestProcessed = 0;
+        std::vector<BufferCache> cachesToRemove;
+        ndk::ScopedAStatus ret =
+                mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+        ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT), ret.getServiceSpecificError());
+        ASSERT_EQ(numRequestProcessed, 0u);
+
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Verify camera offline session behavior
+TEST_P(CameraAidlTest, switchToOffline) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    AvailableStream threshold = {kMaxStillWidth, kMaxStillHeight,
+                                 static_cast<int32_t>(PixelFormat::BLOB)};
+    int64_t bufferId = 1;
+    int32_t frameNumber = 1;
+    CameraMetadata settings;
+
+    for (const auto& name : cameraDeviceNames) {
+        CameraMetadata meta;
+        {
+            std::shared_ptr<ICameraDevice> unusedDevice;
+            openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+                                   &unusedDevice);
+            camera_metadata_t* staticMetaBuffer = clone_camera_metadata(
+                    reinterpret_cast<camera_metadata_t*>(meta.metadata.data()));
+            ::android::hardware::camera::common::V1_0::helper::CameraMetadata staticMeta(
+                    staticMetaBuffer);
+
+            if (isOfflineSessionSupported(staticMetaBuffer) != Status::OK) {
+                ndk::ScopedAStatus ret = mSession->close();
+                mSession = nullptr;
+                ASSERT_TRUE(ret.isOk());
+                continue;
+            }
+            ndk::ScopedAStatus ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+        }
+
+        bool supportsPartialResults = false;
+        int32_t partialResultCount = 0;
+        Stream stream;
+        std::vector<HalStream> halStreams;
+        std::shared_ptr<DeviceCb> cb;
+        int32_t jpegBufferSize;
+        bool useHalBufManager;
+        configureOfflineStillStream(name, mProvider, &threshold, &mSession /*out*/, &stream /*out*/,
+                                    &halStreams /*out*/, &supportsPartialResults /*out*/,
+                                    &partialResultCount /*out*/, &cb /*out*/,
+                                    &jpegBufferSize /*out*/, &useHalBufManager /*out*/);
+
+        auto ret = mSession->constructDefaultRequestSettings(RequestTemplate::STILL_CAPTURE,
+                                                             &settings);
+        ASSERT_TRUE(ret.isOk());
+
+        ::aidl::android::hardware::common::fmq::MQDescriptor<
+                int8_t, aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+                descriptor;
+
+        ndk::ScopedAStatus resultQueueRet = mSession->getCaptureResultMetadataQueue(&descriptor);
+        ASSERT_TRUE(resultQueueRet.isOk());
+        std::shared_ptr<ResultMetadataQueue> resultQueue =
+                std::make_shared<ResultMetadataQueue>(descriptor);
+        if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
+            ALOGE("%s: HAL returns empty result metadata fmq, not use it", __func__);
+            resultQueue = nullptr;
+            // Don't use the queue onwards.
+        }
+
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata requestMeta;
+
+        std::vector<buffer_handle_t> buffers(kBurstFrameCount);
+        std::vector<std::shared_ptr<InFlightRequest>> inflightReqs(kBurstFrameCount);
+        std::vector<CameraMetadata> requestSettings(kBurstFrameCount);
+
+        std::vector<CaptureRequest> requests(kBurstFrameCount);
+
+        HalStream halStream = halStreams[0];
+        for (uint32_t i = 0; i < kBurstFrameCount; i++) {
+            CaptureRequest& request = requests[i];
+            std::vector<StreamBuffer>& outputBuffers = request.outputBuffers;
+            outputBuffers.resize(1);
+            StreamBuffer& outputBuffer = outputBuffers[0];
+
+            std::unique_lock<std::mutex> l(mLock);
+            if (useHalBufManager) {
+                outputBuffer = {halStream.id,  0, NativeHandle(), BufferStatus::OK, NativeHandle(),
+                                NativeHandle()};
+            } else {
+                // jpeg buffer (w,h) = (blobLen, 1)
+                allocateGraphicBuffer(jpegBufferSize, /*height*/ 1,
+                                      android_convertGralloc1To0Usage(
+                                              static_cast<uint64_t>(halStream.producerUsage),
+                                              static_cast<uint64_t>(halStream.consumerUsage)),
+                                      halStream.overrideFormat, &buffers[i]);
+                outputBuffer = {halStream.id,     bufferId + i,   ::android::makeToAidl(buffers[i]),
+                                BufferStatus::OK, NativeHandle(), NativeHandle()};
+            }
+
+            requestMeta.clear();
+            requestMeta.append(reinterpret_cast<camera_metadata_t*>(settings.metadata.data()));
+
+            camera_metadata_t* metaBuffer = requestMeta.release();
+            uint8_t* rawMetaBuffer = reinterpret_cast<uint8_t*>(metaBuffer);
+            requestSettings[i].metadata = std::vector(
+                    rawMetaBuffer, rawMetaBuffer + get_camera_metadata_size(metaBuffer));
+            overrideRotateAndCrop(&requestSettings[i]);
+
+            request.frameNumber = frameNumber + i;
+            request.fmqSettingsSize = 0;
+            request.settings = requestSettings[i];
+            request.inputBuffer = {/*streamId*/ -1,
+                                   /*bufferId*/ 0,      NativeHandle(),
+                                   BufferStatus::ERROR, NativeHandle(),
+                                   NativeHandle()};
+
+            inflightReqs[i] = std::make_shared<InFlightRequest>(1, false, supportsPartialResults,
+                                                                partialResultCount, resultQueue);
+            mInflightMap[frameNumber + i] = inflightReqs[i];
+        }
+
+        int32_t numRequestProcessed = 0;
+        std::vector<BufferCache> cachesToRemove;
+
+        ndk::ScopedAStatus returnStatus =
+                mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(numRequestProcessed, kBurstFrameCount);
+
+        std::vector<int32_t> offlineStreamIds = {halStream.id};
+        CameraOfflineSessionInfo offlineSessionInfo;
+        std::shared_ptr<ICameraOfflineSession> offlineSession;
+        returnStatus =
+                mSession->switchToOffline(offlineStreamIds, &offlineSessionInfo, &offlineSession);
+
+        if (!halStreams[0].supportOffline) {
+            ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT),
+                      returnStatus.getServiceSpecificError());
+            ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        ASSERT_TRUE(returnStatus.isOk());
+        // Hal might be unable to find any requests qualified for offline mode.
+        if (offlineSession == nullptr) {
+            ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        ASSERT_EQ(offlineSessionInfo.offlineStreams.size(), 1u);
+        ASSERT_EQ(offlineSessionInfo.offlineStreams[0].id, halStream.id);
+        ASSERT_NE(offlineSessionInfo.offlineRequests.size(), 0u);
+
+        // close device session to make sure offline session does not rely on it
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+
+        ::aidl::android::hardware::common::fmq::MQDescriptor<
+                int8_t, aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+                offlineResultDescriptor;
+
+        auto offlineResultQueueRet =
+                offlineSession->getCaptureResultMetadataQueue(&offlineResultDescriptor);
+        std::shared_ptr<ResultMetadataQueue> offlineResultQueue =
+                std::make_shared<ResultMetadataQueue>(descriptor);
+        if (!offlineResultQueue->isValid() || offlineResultQueue->availableToWrite() <= 0) {
+            ALOGE("%s: offline session returns empty result metadata fmq, not use it", __func__);
+            offlineResultQueue = nullptr;
+            // Don't use the queue onwards.
+        }
+        ASSERT_TRUE(offlineResultQueueRet.isOk());
+
+        updateInflightResultQueue(offlineResultQueue);
+
+        ret = offlineSession->setCallback(cb);
+        ASSERT_TRUE(ret.isOk());
+
+        for (size_t i = 0; i < kBurstFrameCount; i++) {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReqs[i]->errorCodeValid && ((0 < inflightReqs[i]->numBuffersLeft) ||
+                                                        (!inflightReqs[i]->haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                               std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+            }
+
+            ASSERT_FALSE(inflightReqs[i]->errorCodeValid);
+            ASSERT_NE(inflightReqs[i]->resultOutputBuffers.size(), 0u);
+            ASSERT_EQ(stream.id, inflightReqs[i]->resultOutputBuffers[0].buffer.streamId);
+            ASSERT_FALSE(inflightReqs[i]->collectedResult.isEmpty());
+        }
+
+        ret = offlineSession->close();
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Check whether an invalid capture request with missing output buffers
+// will be reported correctly.
+TEST_P(CameraAidlTest, processCaptureRequestInvalidBuffer) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::vector<AvailableStream> outputBlobStreams;
+    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                        static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+    int32_t frameNumber = 1;
+    CameraMetadata settings;
+
+    for (const auto& name : cameraDeviceNames) {
+        Stream previewStream;
+        std::vector<HalStream> halStreams;
+        std::shared_ptr<DeviceCb> cb;
+        bool supportsPartialResults = false;
+        bool useHalBufManager = false;
+        int32_t partialResultCount = 0;
+        configurePreviewStream(name, mProvider, &previewThreshold, &mSession /*out*/,
+                               &previewStream /*out*/, &halStreams /*out*/,
+                               &supportsPartialResults /*out*/, &partialResultCount /*out*/,
+                               &useHalBufManager /*out*/, &cb /*out*/);
+
+        RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+        ndk::ScopedAStatus ret = mSession->constructDefaultRequestSettings(reqTemplate, &settings);
+        ASSERT_TRUE(ret.isOk());
+        overrideRotateAndCrop(&settings);
+
+        std::vector<CaptureRequest> requests(1);
+        CaptureRequest& request = requests[0];
+        std::vector<StreamBuffer>& outputBuffers = request.outputBuffers;
+        outputBuffers.resize(1);
+        // Empty output buffer
+        outputBuffers[0] = {
+                -1, 0, NativeHandle(), BufferStatus::ERROR, NativeHandle(), NativeHandle()};
+
+        request.inputBuffer = {
+                -1, 0, NativeHandle(), BufferStatus::ERROR, NativeHandle(), NativeHandle()};
+        request.frameNumber = frameNumber;
+        request.fmqSettingsSize = 0;
+        request.settings = settings;
+
+        // Output buffers are missing, we should fail here
+        int32_t numRequestProcessed = 0;
+        std::vector<BufferCache> cachesToRemove;
+        ret = mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+        ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT), ret.getServiceSpecificError());
+        ASSERT_EQ(numRequestProcessed, 0u);
+
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Generate, trigger and flush a preview request
+TEST_P(CameraAidlTest, flushPreviewRequest) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::vector<AvailableStream> outputPreviewStreams;
+    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                        static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+    int64_t bufferId = 1;
+    int32_t frameNumber = 1;
+    CameraMetadata settings;
+
+    for (const auto& name : cameraDeviceNames) {
+        Stream previewStream;
+        std::vector<HalStream> halStreams;
+        std::shared_ptr<DeviceCb> cb;
+        bool supportsPartialResults = false;
+        bool useHalBufManager = false;
+        int32_t partialResultCount = 0;
+
+        configurePreviewStream(name, mProvider, &previewThreshold, &mSession /*out*/,
+                               &previewStream /*out*/, &halStreams /*out*/,
+                               &supportsPartialResults /*out*/, &partialResultCount /*out*/,
+                               &useHalBufManager /*out*/, &cb /*out*/);
+
+        ASSERT_NE(mSession, nullptr);
+        ASSERT_NE(cb, nullptr);
+        ASSERT_FALSE(halStreams.empty());
+
+        ::aidl::android::hardware::common::fmq::MQDescriptor<
+                int8_t, aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+                descriptor;
+
+        auto resultQueueRet = mSession->getCaptureResultMetadataQueue(&descriptor);
+        std::shared_ptr<ResultMetadataQueue> resultQueue =
+                std::make_shared<ResultMetadataQueue>(descriptor);
+        ASSERT_TRUE(resultQueueRet.isOk());
+        if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
+            ALOGE("%s: HAL returns empty result metadata fmq, not use it", __func__);
+            resultQueue = nullptr;
+            // Don't use the queue onwards.
+        }
+
+        std::shared_ptr<InFlightRequest> inflightReq = std::make_shared<InFlightRequest>(
+                1, false, supportsPartialResults, partialResultCount, resultQueue);
+        RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+
+        ndk::ScopedAStatus ret = mSession->constructDefaultRequestSettings(reqTemplate, &settings);
+        ASSERT_TRUE(ret.isOk());
+        overrideRotateAndCrop(&settings);
+
+        buffer_handle_t buffer_handle;
+        std::vector<CaptureRequest> requests(1);
+        CaptureRequest& request = requests[0];
+        std::vector<StreamBuffer>& outputBuffers = request.outputBuffers;
+        outputBuffers.resize(1);
+        StreamBuffer& outputBuffer = outputBuffers[0];
+        if (useHalBufManager) {
+            bufferId = 0;
+            outputBuffer = {halStreams[0].id, bufferId,       NativeHandle(),
+                            BufferStatus::OK, NativeHandle(), NativeHandle()};
+        } else {
+            allocateGraphicBuffer(previewStream.width, previewStream.height,
+                                  android_convertGralloc1To0Usage(
+                                          static_cast<uint64_t>(halStreams[0].producerUsage),
+                                          static_cast<uint64_t>(halStreams[0].consumerUsage)),
+                                  halStreams[0].overrideFormat, &buffer_handle);
+            outputBuffer = {halStreams[0].id, bufferId,       ::android::makeToAidl(buffer_handle),
+                            BufferStatus::OK, NativeHandle(), NativeHandle()};
+        }
+
+        request.frameNumber = frameNumber;
+        request.fmqSettingsSize = 0;
+        request.settings = settings;
+        request.inputBuffer = {
+                -1, 0, NativeHandle(), BufferStatus::ERROR, NativeHandle(), NativeHandle()};
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            mInflightMap.clear();
+            mInflightMap[frameNumber] = inflightReq;
+        }
+
+        int32_t numRequestProcessed = 0;
+        std::vector<BufferCache> cachesToRemove;
+        ret = mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(numRequestProcessed, 1u);
+
+        // Flush before waiting for request to complete.
+        ndk::ScopedAStatus returnStatus = mSession->flush();
+        ASSERT_TRUE(returnStatus.isOk());
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReq->errorCodeValid &&
+                   ((0 < inflightReq->numBuffersLeft) || (!inflightReq->haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                               std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+            }
+
+            if (!inflightReq->errorCodeValid) {
+                ASSERT_NE(inflightReq->resultOutputBuffers.size(), 0u);
+                ASSERT_EQ(previewStream.id, inflightReq->resultOutputBuffers[0].buffer.streamId);
+            } else {
+                switch (inflightReq->errorCode) {
+                    case ErrorCode::ERROR_REQUEST:
+                    case ErrorCode::ERROR_RESULT:
+                    case ErrorCode::ERROR_BUFFER:
+                        // Expected
+                        break;
+                    case ErrorCode::ERROR_DEVICE:
+                    default:
+                        FAIL() << "Unexpected error:"
+                               << static_cast<uint32_t>(inflightReq->errorCode);
+                }
+            }
+        }
+
+        if (useHalBufManager) {
+            verifyBuffersReturned(mSession, previewStream.id, cb);
+        }
+
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Verify that camera flushes correctly without any pending requests.
+TEST_P(CameraAidlTest, flushEmpty) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::vector<AvailableStream> outputPreviewStreams;
+    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                        static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+
+    for (const auto& name : cameraDeviceNames) {
+        Stream previewStream;
+        std::vector<HalStream> halStreams;
+        std::shared_ptr<DeviceCb> cb;
+        bool supportsPartialResults = false;
+        bool useHalBufManager = false;
+
+        int32_t partialResultCount = 0;
+        configurePreviewStream(name, mProvider, &previewThreshold, &mSession /*out*/,
+                               &previewStream /*out*/, &halStreams /*out*/,
+                               &supportsPartialResults /*out*/, &partialResultCount /*out*/,
+                               &useHalBufManager /*out*/, &cb /*out*/);
+
+        ndk::ScopedAStatus returnStatus = mSession->flush();
+        ASSERT_TRUE(returnStatus.isOk());
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            auto timeout = std::chrono::system_clock::now() +
+                           std::chrono::milliseconds(kEmptyFlushTimeoutMSec);
+            ASSERT_EQ(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+        }
+
+        ndk::ScopedAStatus ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Test camera provider notify method
+TEST_P(CameraAidlTest, providerDeviceStateNotification) {
+    notifyDeviceState(ICameraProvider::DEVICE_STATE_BACK_COVERED);
+    notifyDeviceState(ICameraProvider::DEVICE_STATE_NORMAL);
+}
+
+// Verify that all supported stream formats and sizes can be configured
+// successfully for injection camera.
+TEST_P(CameraAidlTest, configureInjectionStreamsAvailableOutputs) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::vector<AvailableStream> outputStreams;
+
+    for (const auto& name : cameraDeviceNames) {
+        CameraMetadata metadata;
+
+        std::shared_ptr<ICameraInjectionSession> injectionSession;
+        std::shared_ptr<ICameraDevice> unusedDevice;
+        openEmptyInjectionSession(name, mProvider, &injectionSession /*out*/, &metadata /*out*/,
+                                  &unusedDevice /*out*/);
+        if (injectionSession == nullptr) {
+            continue;
+        }
+
+        camera_metadata_t* staticMetaBuffer =
+                reinterpret_cast<camera_metadata_t*>(metadata.metadata.data());
+        CameraMetadata chars;
+        chars.metadata = metadata.metadata;
+
+        outputStreams.clear();
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMetaBuffer, outputStreams));
+        ASSERT_NE(0u, outputStreams.size());
+
+        int32_t jpegBufferSize = 0;
+        ASSERT_EQ(Status::OK, getJpegBufferSize(staticMetaBuffer, &jpegBufferSize));
+        ASSERT_NE(0u, jpegBufferSize);
+
+        int32_t streamId = 0;
+        int32_t streamConfigCounter = 0;
+        for (auto& it : outputStreams) {
+            Dataspace dataspace = getDataspace(static_cast<PixelFormat>(it.format));
+            Stream stream = {streamId,
+                             StreamType::OUTPUT,
+                             it.width,
+                             it.height,
+                             static_cast<PixelFormat>(it.format),
+                             static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                                     GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
+                             dataspace,
+                             StreamRotation::ROTATION_0,
+                             std::string(),
+                             jpegBufferSize,
+                             0,
+                             {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                             RequestAvailableDynamicRangeProfilesMap::
+                                     ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+
+            std::vector<Stream> streams = {stream};
+            StreamConfiguration config;
+            createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
+                                      jpegBufferSize);
+
+            config.streamConfigCounter = streamConfigCounter++;
+            ndk::ScopedAStatus s = injectionSession->configureInjectionStreams(config, chars);
+            ASSERT_TRUE(s.isOk());
+            streamId++;
+        }
+
+        std::shared_ptr<ICameraDeviceSession> session;
+        ndk::ScopedAStatus ret = injectionSession->getCameraDeviceSession(&session);
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_NE(session, nullptr);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Check for correct handling of invalid/incorrect configuration parameters for injection camera.
+TEST_P(CameraAidlTest, configureInjectionStreamsInvalidOutputs) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::vector<AvailableStream> outputStreams;
+
+    for (const auto& name : cameraDeviceNames) {
+        CameraMetadata metadata;
+        std::shared_ptr<ICameraInjectionSession> injectionSession;
+        std::shared_ptr<ICameraDevice> unusedDevice;
+        openEmptyInjectionSession(name, mProvider, &injectionSession /*out*/, &metadata /*out*/,
+                                  &unusedDevice);
+        if (injectionSession == nullptr) {
+            continue;
+        }
+
+        camera_metadata_t* staticMetaBuffer =
+                reinterpret_cast<camera_metadata_t*>(metadata.metadata.data());
+        std::shared_ptr<ICameraDeviceSession> session;
+        ndk::ScopedAStatus ret = injectionSession->getCameraDeviceSession(&session);
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_NE(session, nullptr);
+
+        CameraMetadata chars;
+        chars.metadata = metadata.metadata;
+
+        outputStreams.clear();
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMetaBuffer, outputStreams));
+        ASSERT_NE(0u, outputStreams.size());
+
+        int32_t jpegBufferSize = 0;
+        ASSERT_EQ(Status::OK, getJpegBufferSize(staticMetaBuffer, &jpegBufferSize));
+        ASSERT_NE(0u, jpegBufferSize);
+
+        int32_t streamId = 0;
+        Stream stream = {streamId++,
+                         StreamType::OUTPUT,
+                         0,
+                         0,
+                         static_cast<PixelFormat>(outputStreams[0].format),
+                         static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                                 GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
+                         Dataspace::UNKNOWN,
+                         StreamRotation::ROTATION_0,
+                         std::string(),
+                         jpegBufferSize,
+                         0,
+                         {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                         RequestAvailableDynamicRangeProfilesMap::
+                                 ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+
+        int32_t streamConfigCounter = 0;
+        std::vector<Stream> streams = {stream};
+        StreamConfiguration config;
+        createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
+                                  jpegBufferSize);
+
+        config.streamConfigCounter = streamConfigCounter++;
+        ndk::ScopedAStatus s = injectionSession->configureInjectionStreams(config, chars);
+        ASSERT_TRUE(
+                (static_cast<int32_t>(Status::ILLEGAL_ARGUMENT) == s.getServiceSpecificError()) ||
+                (static_cast<int32_t>(Status::INTERNAL_ERROR) == s.getServiceSpecificError()));
+
+        stream = {streamId++,
+                  StreamType::OUTPUT,
+                  INT32_MAX,
+                  INT32_MAX,
+                  static_cast<PixelFormat>(outputStreams[0].format),
+                  static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                          GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
+                  Dataspace::UNKNOWN,
+                  StreamRotation::ROTATION_0,
+                  std::string(),
+                  jpegBufferSize,
+                  0,
+                  {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                  RequestAvailableDynamicRangeProfilesMap::
+                          ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+
+        streams[0] = stream;
+        createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
+                                  jpegBufferSize);
+        config.streamConfigCounter = streamConfigCounter++;
+        s = injectionSession->configureInjectionStreams(config, chars);
+        ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT), s.getServiceSpecificError());
+
+        for (auto& it : outputStreams) {
+            stream = {streamId++,
+                      StreamType::OUTPUT,
+                      it.width,
+                      it.height,
+                      static_cast<PixelFormat>(INT32_MAX),
+                      static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                              GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
+                      Dataspace::UNKNOWN,
+                      StreamRotation::ROTATION_0,
+                      std::string(),
+                      jpegBufferSize,
+                      0,
+                      {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                      RequestAvailableDynamicRangeProfilesMap::
+                              ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+            streams[0] = stream;
+            createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
+                                      jpegBufferSize);
+            config.streamConfigCounter = streamConfigCounter++;
+            s = injectionSession->configureInjectionStreams(config, chars);
+            ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT), s.getServiceSpecificError());
+
+            stream = {streamId++,
+                      StreamType::OUTPUT,
+                      it.width,
+                      it.height,
+                      static_cast<PixelFormat>(it.format),
+                      static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                              GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
+                      Dataspace::UNKNOWN,
+                      static_cast<StreamRotation>(INT32_MAX),
+                      std::string(),
+                      jpegBufferSize,
+                      0,
+                      {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                      RequestAvailableDynamicRangeProfilesMap::
+                              ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+            streams[0] = stream;
+            createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
+                                      jpegBufferSize);
+            config.streamConfigCounter = streamConfigCounter++;
+            s = injectionSession->configureInjectionStreams(config, chars);
+            ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT), s.getServiceSpecificError());
+        }
+
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Check whether session parameters are supported for injection camera. If Hal support for them
+// exist, then try to configure a preview stream using them.
+TEST_P(CameraAidlTest, configureInjectionStreamsWithSessionParameters) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::vector<AvailableStream> outputPreviewStreams;
+    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                        static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+
+    for (const auto& name : cameraDeviceNames) {
+        CameraMetadata metadata;
+        std::shared_ptr<ICameraInjectionSession> injectionSession;
+        std::shared_ptr<ICameraDevice> unusedDevice;
+        openEmptyInjectionSession(name, mProvider, &injectionSession /*out*/, &metadata /*out*/,
+                                  &unusedDevice /*out*/);
+        if (injectionSession == nullptr) {
+            continue;
+        }
+
+        std::shared_ptr<ICameraDeviceSession> session;
+        ndk::ScopedAStatus ret = injectionSession->getCameraDeviceSession(&session);
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_NE(session, nullptr);
+
+        camera_metadata_t* staticMetaBuffer =
+                reinterpret_cast<camera_metadata_t*>(metadata.metadata.data());
+        CameraMetadata chars;
+        chars.metadata = metadata.metadata;
+
+        std::unordered_set<int32_t> availableSessionKeys;
+        Status rc = getSupportedKeys(staticMetaBuffer, ANDROID_REQUEST_AVAILABLE_SESSION_KEYS,
+                                     &availableSessionKeys);
+        ASSERT_EQ(Status::OK, rc);
+        if (availableSessionKeys.empty()) {
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        android::hardware::camera::common::V1_0::helper::CameraMetadata previewRequestSettings;
+        android::hardware::camera::common::V1_0::helper::CameraMetadata sessionParams,
+                modifiedSessionParams;
+        constructFilteredSettings(session, availableSessionKeys, RequestTemplate::PREVIEW,
+                                  &previewRequestSettings, &sessionParams);
+        if (sessionParams.isEmpty()) {
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        outputPreviewStreams.clear();
+
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMetaBuffer, outputPreviewStreams,
+                                                        &previewThreshold));
+        ASSERT_NE(0u, outputPreviewStreams.size());
+
+        Stream previewStream = {
+                0,
+                StreamType::OUTPUT,
+                outputPreviewStreams[0].width,
+                outputPreviewStreams[0].height,
+                static_cast<PixelFormat>(outputPreviewStreams[0].format),
+                static_cast<::aidl::android::hardware::graphics::common::BufferUsage>(
+                        GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
+                Dataspace::UNKNOWN,
+                StreamRotation::ROTATION_0,
+                std::string(),
+                0,
+                -1,
+                {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                RequestAvailableDynamicRangeProfilesMap::
+                        ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+        std::vector<Stream> streams = {previewStream};
+        StreamConfiguration config;
+        config.streams = streams;
+        config.operationMode = StreamConfigurationMode::NORMAL_MODE;
+
+        modifiedSessionParams = sessionParams;
+        camera_metadata_t* sessionParamsBuffer = sessionParams.release();
+        uint8_t* rawSessionParamsBuffer = reinterpret_cast<uint8_t*>(sessionParamsBuffer);
+        config.sessionParams.metadata =
+                std::vector(rawSessionParamsBuffer,
+                            rawSessionParamsBuffer + get_camera_metadata_size(sessionParamsBuffer));
+
+        config.streamConfigCounter = 0;
+        config.streamConfigCounter = 0;
+        config.multiResolutionInputImage = false;
+
+        ndk::ScopedAStatus s = injectionSession->configureInjectionStreams(config, chars);
+        ASSERT_TRUE(s.isOk());
+
+        sessionParams.acquire(sessionParamsBuffer);
+        free_camera_metadata(staticMetaBuffer);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Verify that  valid stream use cases can be configured successfully, and invalid use cases
+// fail stream configuration.
+TEST_P(CameraAidlTest, configureStreamsUseCases) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+
+    for (const auto& name : cameraDeviceNames) {
+        CameraMetadata meta;
+        std::shared_ptr<ICameraDevice> cameraDevice;
+
+        openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+                               &cameraDevice /*out*/);
+
+        camera_metadata_t* staticMeta = reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
+        // Check if camera support depth only
+        if (isDepthOnly(staticMeta)) {
+            ndk::ScopedAStatus ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        std::vector<AvailableStream> outputPreviewStreams;
+        AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                            static_cast<int32_t>(PixelFormat::YCBCR_420_888)};
+        ASSERT_EQ(Status::OK,
+                  getAvailableOutputStreams(staticMeta, outputPreviewStreams, &previewThreshold));
+        ASSERT_NE(0u, outputPreviewStreams.size());
+
+        // Combine valid and invalid stream use cases
+        std::vector<int64_t> useCases(kMandatoryUseCases);
+        useCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL + 1);
+
+        std::vector<int64_t> supportedUseCases;
+        camera_metadata_ro_entry entry;
+        auto retcode = find_camera_metadata_ro_entry(
+                staticMeta, ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES, &entry);
+        if ((0 == retcode) && (entry.count > 0)) {
+            supportedUseCases.insert(supportedUseCases.end(), entry.data.i32,
+                                     entry.data.i32 + entry.count);
+        } else {
+            supportedUseCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
+        }
+
+        std::vector<Stream> streams(1);
+        streams[0] = {0,
+                      StreamType::OUTPUT,
+                      outputPreviewStreams[0].width,
+                      outputPreviewStreams[0].height,
+                      static_cast<PixelFormat>(outputPreviewStreams[0].format),
+                      static_cast<::aidl::android::hardware::graphics::common::BufferUsage>(
+                              GRALLOC1_CONSUMER_USAGE_CPU_READ),
+                      Dataspace::UNKNOWN,
+                      StreamRotation::ROTATION_0,
+                      std::string(),
+                      0,
+                      -1,
+                      {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                      RequestAvailableDynamicRangeProfilesMap::
+                              ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+
+        int32_t streamConfigCounter = 0;
+        CameraMetadata req;
+        StreamConfiguration config;
+        RequestTemplate reqTemplate = RequestTemplate::STILL_CAPTURE;
+        ndk::ScopedAStatus ret = mSession->constructDefaultRequestSettings(reqTemplate, &req);
+        ASSERT_TRUE(ret.isOk());
+        config.sessionParams = req;
+
+        for (int64_t useCase : useCases) {
+            bool useCaseSupported = std::find(supportedUseCases.begin(), supportedUseCases.end(),
+                                              useCase) != supportedUseCases.end();
+
+            streams[0].useCase = static_cast<
+                    aidl::android::hardware::camera::metadata::ScalerAvailableStreamUseCases>(
+                    useCase);
+            config.streams = streams;
+            config.operationMode = StreamConfigurationMode::NORMAL_MODE;
+            config.streamConfigCounter = streamConfigCounter;
+            config.multiResolutionInputImage = false;
+
+            bool combSupported;
+            ret = cameraDevice->isStreamCombinationSupported(config, &combSupported);
+            ASSERT_TRUE((ret.isOk()) || (static_cast<int32_t>(Status::OPERATION_NOT_SUPPORTED) ==
+                                         ret.getServiceSpecificError()));
+            if (ret.isOk()) {
+                ASSERT_EQ(combSupported, useCaseSupported);
+            }
+            ASSERT_TRUE(ret.isOk());
+
+            std::vector<HalStream> halStreams;
+            ret = mSession->configureStreams(config, &halStreams);
+            ALOGI("configureStreams returns status: %d", ret.getServiceSpecificError());
+            if (useCaseSupported) {
+                ASSERT_TRUE(ret.isOk());
+                ASSERT_EQ(1u, halStreams.size());
+            } else {
+                ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT),
+                          ret.getServiceSpecificError());
+            }
+        }
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CameraAidlTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, CameraAidlTest,
+        testing::ValuesIn(android::getAidlHalInstanceNames(ICameraProvider::descriptor)),
+        android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
new file mode 100644
index 0000000..fd83e37
--- /dev/null
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -0,0 +1,2947 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "camera_aidl_test.h"
+
+#include <inttypes.h>
+
+#include <CameraParameters.h>
+#include <HandleImporter.h>
+#include <aidl/android/hardware/camera/device/ICameraDevice.h>
+#include <aidl/android/hardware/camera/metadata/CameraMetadataTag.h>
+#include <aidl/android/hardware/camera/metadata/RequestAvailableDynamicRangeProfilesMap.h>
+#include <aidl/android/hardware/camera/metadata/SensorInfoColorFilterArrangement.h>
+#include <aidl/android/hardware/camera/metadata/SensorPixelMode.h>
+#include <aidl/android/hardware/camera/provider/BnCameraProviderCallback.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <device_cb.h>
+#include <empty_device_cb.h>
+#include <grallocusage/GrallocUsageConversion.h>
+#include <hardware/gralloc1.h>
+#include <simple_device_cb.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <regex>
+#include <typeinfo>
+
+using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
+using ::aidl::android::hardware::camera::common::TorchModeStatus;
+using ::aidl::android::hardware::camera::device::CameraMetadata;
+using ::aidl::android::hardware::camera::device::ICameraDevice;
+using ::aidl::android::hardware::camera::metadata::CameraMetadataTag;
+using ::aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap;
+using ::aidl::android::hardware::camera::metadata::SensorInfoColorFilterArrangement;
+using ::aidl::android::hardware::camera::metadata::SensorPixelMode;
+using ::aidl::android::hardware::camera::provider::BnCameraProviderCallback;
+using ::aidl::android::hardware::camera::provider::ConcurrentCameraIdCombination;
+using ::aidl::android::hardware::camera::provider::ICameraProvider;
+using ::aidl::android::hardware::common::NativeHandle;
+using ::android::hardware::camera::common::V1_0::helper::Size;
+using ::ndk::ScopedAStatus;
+using ::ndk::SpAIBinder;
+
+namespace {
+bool matchDeviceName(const std::string& deviceName, const std::string& providerType,
+                     std::string* deviceVersion, std::string* cameraId) {
+    // expected format: device@<major>.<minor>/<type>/<id>
+    std::stringstream pattern;
+    pattern << "device@[0-9]+\\.[0-9]+/" << providerType << "/(.+)";
+    std::regex e(pattern.str());
+
+    std::smatch sm;
+    if (std::regex_match(deviceName, sm, e)) {
+        if (deviceVersion != nullptr) {
+            *deviceVersion = sm[1];
+        }
+        if (cameraId != nullptr) {
+            *cameraId = sm[2];
+        }
+        return true;
+    }
+    return false;
+}
+
+bool parseProviderName(const std::string& serviceDescriptor, std::string* type /*out*/,
+                       uint32_t* id /*out*/) {
+    if (!type || !id) {
+        ADD_FAILURE();
+        return false;
+    }
+
+    // expected format: <service_name>/<type>/<id>
+    std::string::size_type slashIdx1 = serviceDescriptor.find('/');
+    if (slashIdx1 == std::string::npos || slashIdx1 == serviceDescriptor.size() - 1) {
+        ADD_FAILURE() << "Provider name does not have / separator between name, type, and id";
+        return false;
+    }
+
+    std::string::size_type slashIdx2 = serviceDescriptor.find('/', slashIdx1 + 1);
+    if (slashIdx2 == std::string::npos || slashIdx2 == serviceDescriptor.size() - 1) {
+        ADD_FAILURE() << "Provider name does not have / separator between type and id";
+        return false;
+    }
+
+    std::string typeVal = serviceDescriptor.substr(slashIdx1 + 1, slashIdx2 - slashIdx1 - 1);
+
+    char* endPtr;
+    errno = 0;
+    int64_t idVal = strtol(serviceDescriptor.c_str() + slashIdx2 + 1, &endPtr, 10);
+    if (errno != 0) {
+        ADD_FAILURE() << "cannot parse provider id as an integer:" << serviceDescriptor.c_str()
+                      << strerror(errno) << errno;
+        return false;
+    }
+    if (endPtr != serviceDescriptor.c_str() + serviceDescriptor.size()) {
+        ADD_FAILURE() << "provider id has unexpected length " << serviceDescriptor.c_str();
+        return false;
+    }
+    if (idVal < 0) {
+        ADD_FAILURE() << "id is negative: " << serviceDescriptor.c_str() << idVal;
+        return false;
+    }
+
+    *type = typeVal;
+    *id = static_cast<uint32_t>(idVal);
+
+    return true;
+}
+
+const std::vector<int64_t> kMandatoryUseCases = {
+        ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+        ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW,
+        ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE,
+        ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD,
+        ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL,
+        ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL};
+}  // namespace
+
+void CameraAidlTest::SetUp() {
+    std::string serviceDescriptor = GetParam();
+    ALOGI("get service with name: %s", serviceDescriptor.c_str());
+
+    bool success = ABinderProcess_setThreadPoolMaxThreadCount(5);
+    ALOGI("ABinderProcess_setThreadPoolMaxThreadCount returns %s", success ? "true" : "false");
+    ASSERT_TRUE(success);
+    ABinderProcess_startThreadPool();
+
+    SpAIBinder cameraProviderBinder =
+            SpAIBinder(AServiceManager_getService(serviceDescriptor.c_str()));
+    ASSERT_NE(cameraProviderBinder.get(), nullptr);
+
+    std::shared_ptr<ICameraProvider> cameraProvider =
+            ICameraProvider::fromBinder(cameraProviderBinder);
+    ASSERT_NE(cameraProvider.get(), nullptr);
+    mProvider = cameraProvider;
+    uint32_t id;
+    ASSERT_TRUE(parseProviderName(serviceDescriptor, &mProviderType, &id));
+
+    notifyDeviceState(ICameraProvider::DEVICE_STATE_NORMAL);
+}
+
+void CameraAidlTest::TearDown() {
+    if (mSession != nullptr) {
+        ndk::ScopedAStatus ret = mSession->close();
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+std::vector<std::string> CameraAidlTest::getCameraDeviceNames(
+        std::shared_ptr<ICameraProvider>& provider, bool addSecureOnly) {
+    std::vector<std::string> cameraDeviceNames;
+
+    ScopedAStatus ret = provider->getCameraIdList(&cameraDeviceNames);
+    if (!ret.isOk()) {
+        ADD_FAILURE() << "Could not get camera id list";
+    }
+
+    // External camera devices are reported through cameraDeviceStatusChange
+    struct ProviderCb : public BnCameraProviderCallback {
+        ScopedAStatus cameraDeviceStatusChange(const std::string& devName,
+                                               CameraDeviceStatus newStatus) override {
+            ALOGI("camera device status callback name %s, status %d", devName.c_str(),
+                  (int)newStatus);
+            if (newStatus == CameraDeviceStatus::PRESENT) {
+                externalCameraDeviceNames.push_back(devName);
+            }
+            return ScopedAStatus::ok();
+        }
+
+        ScopedAStatus torchModeStatusChange(const std::string&, TorchModeStatus) override {
+            return ScopedAStatus::ok();
+        }
+
+        ScopedAStatus physicalCameraDeviceStatusChange(
+                const std::string&, const std::string&,
+                ::aidl::android::hardware::camera::common::CameraDeviceStatus) override {
+            return ndk::ScopedAStatus();
+        }
+
+        std::vector<std::string> externalCameraDeviceNames;
+    };
+    std::shared_ptr<ProviderCb> cb = ndk::SharedRefBase::make<ProviderCb>();
+    auto status = mProvider->setCallback(cb);
+
+    for (const auto& devName : cb->externalCameraDeviceNames) {
+        if (cameraDeviceNames.end() ==
+            std::find(cameraDeviceNames.begin(), cameraDeviceNames.end(), devName)) {
+            cameraDeviceNames.push_back(devName);
+        }
+    }
+
+    std::vector<std::string> retList;
+    for (auto& cameraDeviceName : cameraDeviceNames) {
+        bool isSecureOnlyCamera = isSecureOnly(mProvider, cameraDeviceName);
+        if (addSecureOnly) {
+            if (isSecureOnlyCamera) {
+                retList.emplace_back(cameraDeviceName);
+            }
+        } else if (!isSecureOnlyCamera) {
+            retList.emplace_back(cameraDeviceName);
+        }
+    }
+    return retList;
+}
+
+bool CameraAidlTest::isSecureOnly(const std::shared_ptr<ICameraProvider>& provider,
+                                  const std::string& name) {
+    std::shared_ptr<ICameraDevice> cameraDevice = nullptr;
+    ScopedAStatus retInterface = provider->getCameraDeviceInterface(name, &cameraDevice);
+    if (!retInterface.isOk()) {
+        ADD_FAILURE() << "Failed to get camera device interface for " << name;
+    }
+
+    CameraMetadata cameraCharacteristics;
+    ScopedAStatus retChars = cameraDevice->getCameraCharacteristics(&cameraCharacteristics);
+    if (!retChars.isOk()) {
+        ADD_FAILURE() << "Failed to get camera characteristics for device " << name;
+    }
+
+    camera_metadata_t* chars =
+            reinterpret_cast<camera_metadata_t*>(cameraCharacteristics.metadata.data());
+
+    SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
+    Status retCameraKind = getSystemCameraKind(chars, &systemCameraKind);
+    if (retCameraKind != Status::OK) {
+        ADD_FAILURE() << "Failed to get camera kind for " << name;
+    }
+
+    return systemCameraKind == SystemCameraKind::HIDDEN_SECURE_CAMERA;
+}
+
+std::map<std::string, std::string> CameraAidlTest::getCameraDeviceIdToNameMap(
+        std::shared_ptr<ICameraProvider> provider) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(provider);
+
+    std::map<std::string, std::string> idToNameMap;
+    for (auto& name : cameraDeviceNames) {
+        std::string version, cameraId;
+        if (!matchDeviceName(name, mProviderType, &version, &cameraId)) {
+            ADD_FAILURE();
+        }
+        idToNameMap.insert(std::make_pair(std::string(cameraId), name));
+    }
+    return idToNameMap;
+}
+
+void CameraAidlTest::verifyMonochromeCameraResult(
+        const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& metadata) {
+    camera_metadata_ro_entry entry;
+
+    // Check tags that are not applicable for monochrome camera
+    ASSERT_FALSE(metadata.exists(ANDROID_SENSOR_GREEN_SPLIT));
+    ASSERT_FALSE(metadata.exists(ANDROID_SENSOR_NEUTRAL_COLOR_POINT));
+    ASSERT_FALSE(metadata.exists(ANDROID_COLOR_CORRECTION_MODE));
+    ASSERT_FALSE(metadata.exists(ANDROID_COLOR_CORRECTION_TRANSFORM));
+    ASSERT_FALSE(metadata.exists(ANDROID_COLOR_CORRECTION_GAINS));
+
+    // Check dynamicBlackLevel
+    entry = metadata.find(ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL);
+    if (entry.count > 0) {
+        ASSERT_EQ(entry.count, 4);
+        for (size_t i = 1; i < entry.count; i++) {
+            ASSERT_FLOAT_EQ(entry.data.f[i], entry.data.f[0]);
+        }
+    }
+
+    // Check noiseProfile
+    entry = metadata.find(ANDROID_SENSOR_NOISE_PROFILE);
+    if (entry.count > 0) {
+        ASSERT_EQ(entry.count, 2);
+    }
+
+    // Check lensShadingMap
+    entry = metadata.find(ANDROID_STATISTICS_LENS_SHADING_MAP);
+    if (entry.count > 0) {
+        ASSERT_EQ(entry.count % 4, 0);
+        for (size_t i = 0; i < entry.count / 4; i++) {
+            ASSERT_FLOAT_EQ(entry.data.f[i * 4 + 1], entry.data.f[i * 4]);
+            ASSERT_FLOAT_EQ(entry.data.f[i * 4 + 2], entry.data.f[i * 4]);
+            ASSERT_FLOAT_EQ(entry.data.f[i * 4 + 3], entry.data.f[i * 4]);
+        }
+    }
+
+    // Check tonemapCurve
+    camera_metadata_ro_entry curveRed = metadata.find(ANDROID_TONEMAP_CURVE_RED);
+    camera_metadata_ro_entry curveGreen = metadata.find(ANDROID_TONEMAP_CURVE_GREEN);
+    camera_metadata_ro_entry curveBlue = metadata.find(ANDROID_TONEMAP_CURVE_BLUE);
+    if (curveRed.count > 0 && curveGreen.count > 0 && curveBlue.count > 0) {
+        ASSERT_EQ(curveRed.count, curveGreen.count);
+        ASSERT_EQ(curveRed.count, curveBlue.count);
+        for (size_t i = 0; i < curveRed.count; i++) {
+            ASSERT_FLOAT_EQ(curveGreen.data.f[i], curveRed.data.f[i]);
+            ASSERT_FLOAT_EQ(curveBlue.data.f[i], curveRed.data.f[i]);
+        }
+    }
+}
+
+void CameraAidlTest::verifyStreamUseCaseCharacteristics(const camera_metadata_t* metadata) {
+    camera_metadata_ro_entry entry;
+    // Check capabilities
+    int retcode =
+            find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+    bool hasStreamUseCaseCap = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        if (std::find(entry.data.u8, entry.data.u8 + entry.count,
+                      ANDROID_REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE) !=
+            entry.data.u8 + entry.count) {
+            hasStreamUseCaseCap = true;
+        }
+    }
+
+    bool supportMandatoryUseCases = false;
+    retcode = find_camera_metadata_ro_entry(metadata, ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES,
+                                            &entry);
+    if ((0 == retcode) && (entry.count > 0)) {
+        supportMandatoryUseCases = true;
+        for (size_t i = 0; i < kMandatoryUseCases.size(); i++) {
+            if (std::find(entry.data.i64, entry.data.i64 + entry.count, kMandatoryUseCases[i]) ==
+                entry.data.i64 + entry.count) {
+                supportMandatoryUseCases = false;
+                break;
+            }
+        }
+        bool supportDefaultUseCase = false;
+        for (size_t i = 0; i < entry.count; i++) {
+            if (entry.data.i64[i] == ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
+                supportDefaultUseCase = true;
+            }
+            ASSERT_TRUE(entry.data.i64[i] <= ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL ||
+                        entry.data.i64[i] >=
+                                ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START);
+        }
+        ASSERT_TRUE(supportDefaultUseCase);
+    }
+
+    ASSERT_EQ(hasStreamUseCaseCap, supportMandatoryUseCases);
+}
+
+Status CameraAidlTest::isMonochromeCamera(const camera_metadata_t* staticMeta) {
+    Status ret = Status::OPERATION_NOT_SUPPORTED;
+    if (nullptr == staticMeta) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                           &entry);
+
+    if (0 != rc) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    for (size_t i = 0; i < entry.count; i++) {
+        if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME == entry.data.u8[i]) {
+            ret = Status::OK;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+Status CameraAidlTest::isLogicalMultiCamera(const camera_metadata_t* staticMeta) {
+    Status ret = Status::OPERATION_NOT_SUPPORTED;
+    if (nullptr == staticMeta) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                           &entry);
+    if (0 != rc) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    for (size_t i = 0; i < entry.count; i++) {
+        if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA == entry.data.u8[i]) {
+            ret = Status::OK;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+void CameraAidlTest::verifyLogicalCameraResult(const camera_metadata_t* staticMetadata,
+                                               const std::vector<uint8_t>& resultMetadata) {
+    camera_metadata_t* metadata = (camera_metadata_t*)resultMetadata.data();
+
+    std::unordered_set<std::string> physicalIds;
+    Status rc = getPhysicalCameraIds(staticMetadata, &physicalIds);
+    ASSERT_TRUE(Status::OK == rc);
+    ASSERT_TRUE(physicalIds.size() > 1);
+
+    camera_metadata_ro_entry entry;
+    // Check mainPhysicalId
+    find_camera_metadata_ro_entry(metadata, ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID,
+                                  &entry);
+    if (entry.count > 0) {
+        std::string mainPhysicalId(reinterpret_cast<const char*>(entry.data.u8));
+        ASSERT_NE(physicalIds.find(mainPhysicalId), physicalIds.end());
+    } else {
+        ADD_FAILURE() << "Get LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID failed!";
+    }
+}
+
+Status CameraAidlTest::getPhysicalCameraIds(const camera_metadata_t* staticMeta,
+                                            std::unordered_set<std::string>* physicalIds) {
+    if ((nullptr == staticMeta) || (nullptr == physicalIds)) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
+                                           &entry);
+    if (0 != rc) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    const uint8_t* ids = entry.data.u8;
+    size_t start = 0;
+    for (size_t i = 0; i < entry.count; i++) {
+        if (ids[i] == '\0') {
+            if (start != i) {
+                std::string currentId(reinterpret_cast<const char*>(ids + start));
+                physicalIds->emplace(currentId);
+            }
+            start = i + 1;
+        }
+    }
+
+    return Status::OK;
+}
+
+Status CameraAidlTest::getSystemCameraKind(const camera_metadata_t* staticMeta,
+                                           SystemCameraKind* systemCameraKind) {
+    if (nullptr == staticMeta || nullptr == systemCameraKind) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_ro_entry entry{};
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                           &entry);
+    if (0 != rc) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (entry.count == 1 &&
+        entry.data.u8[0] == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA) {
+        *systemCameraKind = SystemCameraKind::HIDDEN_SECURE_CAMERA;
+        return Status::OK;
+    }
+
+    // Go through the capabilities and check if it has
+    // ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA
+    for (size_t i = 0; i < entry.count; ++i) {
+        uint8_t capability = entry.data.u8[i];
+        if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA) {
+            *systemCameraKind = SystemCameraKind::SYSTEM_ONLY_CAMERA;
+            return Status::OK;
+        }
+    }
+    *systemCameraKind = SystemCameraKind::PUBLIC;
+    return Status::OK;
+}
+
+void CameraAidlTest::notifyDeviceState(int64_t state) {
+    if (mProvider == nullptr) {
+        return;
+    }
+    mProvider->notifyDeviceStateChange(state);
+}
+
+void CameraAidlTest::allocateGraphicBuffer(uint32_t width, uint32_t height, uint64_t usage,
+                                           PixelFormat format, buffer_handle_t* buffer_handle) {
+    ASSERT_NE(buffer_handle, nullptr);
+
+    uint32_t stride;
+
+    android::status_t err = android::GraphicBufferAllocator::get().allocateRawHandle(
+            width, height, static_cast<int32_t>(format), 1u /*layerCount*/, usage, buffer_handle,
+            &stride, "VtsHalCameraProviderV2");
+    ASSERT_EQ(err, android::NO_ERROR);
+}
+
+bool CameraAidlTest::matchDeviceName(const std::string& deviceName, const std::string& providerType,
+                                     std::string* deviceVersion, std::string* cameraId) {
+    // "device@<version>/legacy/<id>"
+    std::string pattern;
+    pattern.append("device@([0-9]+\\.[0-9]+)/");
+    pattern.append(providerType);
+    pattern.append("/(.+)");
+
+    std::regex e(pattern);
+    std::smatch sm;
+    if (std::regex_match(deviceName, sm, e)) {
+        if (deviceVersion != nullptr) {
+            *deviceVersion = sm[1];
+        }
+        if (cameraId != nullptr) {
+            *cameraId = sm[2];
+        }
+        return true;
+    }
+    return false;
+}
+
+void CameraAidlTest::verifyCameraCharacteristics(const CameraMetadata& chars) {
+    const camera_metadata_t* metadata =
+            reinterpret_cast<const camera_metadata_t*>(chars.metadata.data());
+
+    size_t expectedSize = chars.metadata.size();
+    int result = validate_camera_metadata_structure(metadata, &expectedSize);
+    ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+    size_t entryCount = get_camera_metadata_entry_count(metadata);
+    // TODO: we can do better than 0 here. Need to check how many required
+    // characteristics keys we've defined.
+    ASSERT_GT(entryCount, 0u);
+
+    camera_metadata_ro_entry entry;
+    int retcode =
+            find_camera_metadata_ro_entry(metadata, ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &entry);
+    if ((0 == retcode) && (entry.count > 0)) {
+        uint8_t hardwareLevel = entry.data.u8[0];
+        ASSERT_TRUE(hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED ||
+                    hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL ||
+                    hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_3 ||
+                    hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL);
+    } else {
+        ADD_FAILURE() << "Get camera hardware level failed!";
+    }
+
+    entry.count = 0;
+    retcode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION, &entry);
+    if ((0 == retcode) || (entry.count > 0)) {
+        ADD_FAILURE() << "ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION "
+                      << " per API contract should never be set by Hal!";
+    }
+    retcode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS, &entry);
+    if ((0 == retcode) || (entry.count > 0)) {
+        ADD_FAILURE() << "ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS"
+                      << " per API contract should never be set by Hal!";
+    }
+    retcode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS, &entry);
+    if ((0 == retcode) || (entry.count > 0)) {
+        ADD_FAILURE() << "ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS"
+                      << " per API contract should never be set by Hal!";
+    }
+    retcode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS, &entry);
+    if ((0 == retcode) || (entry.count > 0)) {
+        ADD_FAILURE() << "ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS"
+                      << " per API contract should never be set by Hal!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS, &entry);
+    if (0 == retcode || entry.count > 0) {
+        ADD_FAILURE() << "ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS "
+                      << " per API contract should never be set by Hal!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS, &entry);
+    if (0 == retcode || entry.count > 0) {
+        ADD_FAILURE() << "ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS "
+                      << " per API contract should never be set by Hal!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata, ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS,
+                                            &entry);
+    if (0 == retcode || entry.count > 0) {
+        ADD_FAILURE() << "ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS "
+                      << " per API contract should never be set by Hal!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata, ANDROID_HEIC_INFO_SUPPORTED, &entry);
+    if (0 == retcode && entry.count > 0) {
+        retcode = find_camera_metadata_ro_entry(
+                metadata, ANDROID_HEIC_INFO_MAX_JPEG_APP_SEGMENTS_COUNT, &entry);
+        if (0 == retcode && entry.count > 0) {
+            uint8_t maxJpegAppSegmentsCount = entry.data.u8[0];
+            ASSERT_TRUE(maxJpegAppSegmentsCount >= 1 && maxJpegAppSegmentsCount <= 16);
+        } else {
+            ADD_FAILURE() << "Get Heic maxJpegAppSegmentsCount failed!";
+        }
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata, ANDROID_LENS_POSE_REFERENCE, &entry);
+    if (0 == retcode && entry.count > 0) {
+        uint8_t poseReference = entry.data.u8[0];
+        ASSERT_TRUE(poseReference <= ANDROID_LENS_POSE_REFERENCE_UNDEFINED &&
+                    poseReference >= ANDROID_LENS_POSE_REFERENCE_PRIMARY_CAMERA);
+    }
+
+    retcode =
+            find_camera_metadata_ro_entry(metadata, ANDROID_INFO_DEVICE_STATE_ORIENTATIONS, &entry);
+    if (0 == retcode && entry.count > 0) {
+        ASSERT_TRUE((entry.count % 2) == 0);
+        uint64_t maxPublicState = ((uint64_t)ICameraProvider::DEVICE_STATE_FOLDED) << 1;
+        uint64_t vendorStateStart = 1UL << 31;  // Reserved for vendor specific states
+        uint64_t stateMask = (1 << vendorStateStart) - 1;
+        stateMask &= ~((1 << maxPublicState) - 1);
+        for (int i = 0; i < entry.count; i += 2) {
+            ASSERT_TRUE((entry.data.i64[i] & stateMask) == 0);
+            ASSERT_TRUE((entry.data.i64[i + 1] % 90) == 0);
+        }
+    }
+
+    verifyExtendedSceneModeCharacteristics(metadata);
+    verifyZoomCharacteristics(metadata);
+    verifyStreamUseCaseCharacteristics(metadata);
+}
+
+void CameraAidlTest::verifyExtendedSceneModeCharacteristics(const camera_metadata_t* metadata) {
+    camera_metadata_ro_entry entry;
+    int retcode = 0;
+
+    retcode = find_camera_metadata_ro_entry(metadata, ANDROID_CONTROL_AVAILABLE_MODES, &entry);
+    if ((0 == retcode) && (entry.count > 0)) {
+        for (auto i = 0; i < entry.count; i++) {
+            ASSERT_TRUE(entry.data.u8[i] >= ANDROID_CONTROL_MODE_OFF &&
+                        entry.data.u8[i] <= ANDROID_CONTROL_MODE_USE_EXTENDED_SCENE_MODE);
+        }
+    } else {
+        ADD_FAILURE() << "Get camera controlAvailableModes failed!";
+    }
+
+    // Check key availability in capabilities, request and result.
+
+    retcode =
+            find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry);
+    bool hasExtendedSceneModeRequestKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasExtendedSceneModeRequestKey =
+                std::find(entry.data.i32, entry.data.i32 + entry.count,
+                          ANDROID_CONTROL_EXTENDED_SCENE_MODE) != entry.data.i32 + entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableRequestKeys failed!";
+    }
+
+    retcode =
+            find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
+    bool hasExtendedSceneModeResultKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasExtendedSceneModeResultKey =
+                std::find(entry.data.i32, entry.data.i32 + entry.count,
+                          ANDROID_CONTROL_EXTENDED_SCENE_MODE) != entry.data.i32 + entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableResultKeys failed!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata,
+                                            ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
+    bool hasExtendedSceneModeMaxSizesKey = false;
+    bool hasExtendedSceneModeZoomRatioRangesKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasExtendedSceneModeMaxSizesKey =
+                std::find(entry.data.i32, entry.data.i32 + entry.count,
+                          ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES) !=
+                entry.data.i32 + entry.count;
+        hasExtendedSceneModeZoomRatioRangesKey =
+                std::find(entry.data.i32, entry.data.i32 + entry.count,
+                          ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES) !=
+                entry.data.i32 + entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!";
+    }
+
+    camera_metadata_ro_entry maxSizesEntry;
+    retcode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES, &maxSizesEntry);
+    bool hasExtendedSceneModeMaxSizes = (0 == retcode && maxSizesEntry.count > 0);
+
+    camera_metadata_ro_entry zoomRatioRangesEntry;
+    retcode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES,
+            &zoomRatioRangesEntry);
+    bool hasExtendedSceneModeZoomRatioRanges = (0 == retcode && zoomRatioRangesEntry.count > 0);
+
+    // Extended scene mode keys must all be available, or all be unavailable.
+    bool noExtendedSceneMode =
+            !hasExtendedSceneModeRequestKey && !hasExtendedSceneModeResultKey &&
+            !hasExtendedSceneModeMaxSizesKey && !hasExtendedSceneModeZoomRatioRangesKey &&
+            !hasExtendedSceneModeMaxSizes && !hasExtendedSceneModeZoomRatioRanges;
+    if (noExtendedSceneMode) {
+        return;
+    }
+    bool hasExtendedSceneMode = hasExtendedSceneModeRequestKey && hasExtendedSceneModeResultKey &&
+                                hasExtendedSceneModeMaxSizesKey &&
+                                hasExtendedSceneModeZoomRatioRangesKey &&
+                                hasExtendedSceneModeMaxSizes && hasExtendedSceneModeZoomRatioRanges;
+    ASSERT_TRUE(hasExtendedSceneMode);
+
+    // Must have DISABLED, and must have one of BOKEH_STILL_CAPTURE, BOKEH_CONTINUOUS, or a VENDOR
+    // mode.
+    ASSERT_TRUE((maxSizesEntry.count == 6 && zoomRatioRangesEntry.count == 2) ||
+                (maxSizesEntry.count == 9 && zoomRatioRangesEntry.count == 4));
+    bool hasDisabledMode = false;
+    bool hasBokehStillCaptureMode = false;
+    bool hasBokehContinuousMode = false;
+    bool hasVendorMode = false;
+    std::vector<AvailableStream> outputStreams;
+    ASSERT_EQ(Status::OK, getAvailableOutputStreams(metadata, outputStreams));
+    for (int i = 0, j = 0; i < maxSizesEntry.count && j < zoomRatioRangesEntry.count; i += 3) {
+        int32_t mode = maxSizesEntry.data.i32[i];
+        int32_t maxWidth = maxSizesEntry.data.i32[i + 1];
+        int32_t maxHeight = maxSizesEntry.data.i32[i + 2];
+        switch (mode) {
+            case ANDROID_CONTROL_EXTENDED_SCENE_MODE_DISABLED:
+                hasDisabledMode = true;
+                ASSERT_TRUE(maxWidth == 0 && maxHeight == 0);
+                break;
+            case ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_STILL_CAPTURE:
+                hasBokehStillCaptureMode = true;
+                j += 2;
+                break;
+            case ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_CONTINUOUS:
+                hasBokehContinuousMode = true;
+                j += 2;
+                break;
+            default:
+                if (mode < ANDROID_CONTROL_EXTENDED_SCENE_MODE_VENDOR_START) {
+                    ADD_FAILURE() << "Invalid extended scene mode advertised: " << mode;
+                } else {
+                    hasVendorMode = true;
+                    j += 2;
+                }
+                break;
+        }
+
+        if (mode != ANDROID_CONTROL_EXTENDED_SCENE_MODE_DISABLED) {
+            // Make sure size is supported.
+            bool sizeSupported = false;
+            for (const auto& stream : outputStreams) {
+                if ((stream.format == static_cast<int32_t>(PixelFormat::YCBCR_420_888) ||
+                     stream.format == static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)) &&
+                    stream.width == maxWidth && stream.height == maxHeight) {
+                    sizeSupported = true;
+                    break;
+                }
+            }
+            ASSERT_TRUE(sizeSupported);
+
+            // Make sure zoom range is valid
+            float minZoomRatio = zoomRatioRangesEntry.data.f[0];
+            float maxZoomRatio = zoomRatioRangesEntry.data.f[1];
+            ASSERT_GT(minZoomRatio, 0.0f);
+            ASSERT_LE(minZoomRatio, maxZoomRatio);
+        }
+    }
+    ASSERT_TRUE(hasDisabledMode);
+    ASSERT_TRUE(hasBokehStillCaptureMode || hasBokehContinuousMode || hasVendorMode);
+}
+
+Status CameraAidlTest::getAvailableOutputStreams(const camera_metadata_t* staticMeta,
+                                                 std::vector<AvailableStream>& outputStreams,
+                                                 const AvailableStream* threshold,
+                                                 bool maxResolution) {
+    AvailableStream depthPreviewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                             static_cast<int32_t>(PixelFormat::Y16)};
+    if (nullptr == staticMeta) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+    int scalerTag = maxResolution
+                            ? ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION
+                            : ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
+    int depthTag = maxResolution
+                           ? ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION
+                           : ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS;
+
+    camera_metadata_ro_entry scalerEntry;
+    camera_metadata_ro_entry depthEntry;
+    int foundScaler = find_camera_metadata_ro_entry(staticMeta, scalerTag, &scalerEntry);
+    int foundDepth = find_camera_metadata_ro_entry(staticMeta, depthTag, &depthEntry);
+    if ((0 != foundScaler || (0 != (scalerEntry.count % 4))) &&
+        (0 != foundDepth || (0 != (depthEntry.count % 4)))) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (foundScaler == 0 && (0 == (scalerEntry.count % 4))) {
+        fillOutputStreams(&scalerEntry, outputStreams, threshold,
+                          ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
+    }
+
+    if (foundDepth == 0 && (0 == (depthEntry.count % 4))) {
+        fillOutputStreams(&depthEntry, outputStreams, &depthPreviewThreshold,
+                          ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT);
+    }
+
+    return Status::OK;
+}
+
+void CameraAidlTest::fillOutputStreams(camera_metadata_ro_entry_t* entry,
+                                       std::vector<AvailableStream>& outputStreams,
+                                       const AvailableStream* threshold,
+                                       const int32_t availableConfigOutputTag) {
+    for (size_t i = 0; i < entry->count; i += 4) {
+        if (availableConfigOutputTag == entry->data.i32[i + 3]) {
+            if (nullptr == threshold) {
+                AvailableStream s = {entry->data.i32[i + 1], entry->data.i32[i + 2],
+                                     entry->data.i32[i]};
+                outputStreams.push_back(s);
+            } else {
+                if ((threshold->format == entry->data.i32[i]) &&
+                    (threshold->width >= entry->data.i32[i + 1]) &&
+                    (threshold->height >= entry->data.i32[i + 2])) {
+                    AvailableStream s = {entry->data.i32[i + 1], entry->data.i32[i + 2],
+                                         threshold->format};
+                    outputStreams.push_back(s);
+                }
+            }
+        }
+    }
+}
+
+void CameraAidlTest::verifyZoomCharacteristics(const camera_metadata_t* metadata) {
+    camera_metadata_ro_entry entry;
+    int retcode = 0;
+
+    // Check key availability in capabilities, request and result.
+    retcode = find_camera_metadata_ro_entry(metadata, ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
+                                            &entry);
+    float maxDigitalZoom = 1.0;
+    if ((0 == retcode) && (entry.count == 1)) {
+        maxDigitalZoom = entry.data.f[0];
+    } else {
+        ADD_FAILURE() << "Get camera scalerAvailableMaxDigitalZoom failed!";
+    }
+
+    retcode =
+            find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry);
+    bool hasZoomRequestKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasZoomRequestKey = std::find(entry.data.i32, entry.data.i32 + entry.count,
+                                      ANDROID_CONTROL_ZOOM_RATIO) != entry.data.i32 + entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableRequestKeys failed!";
+    }
+
+    retcode =
+            find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
+    bool hasZoomResultKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasZoomResultKey = std::find(entry.data.i32, entry.data.i32 + entry.count,
+                                     ANDROID_CONTROL_ZOOM_RATIO) != entry.data.i32 + entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableResultKeys failed!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata,
+                                            ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
+    bool hasZoomCharacteristicsKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasZoomCharacteristicsKey =
+                std::find(entry.data.i32, entry.data.i32 + entry.count,
+                          ANDROID_CONTROL_ZOOM_RATIO_RANGE) != entry.data.i32 + entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata, ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+    bool hasZoomRatioRange = (0 == retcode && entry.count == 2);
+
+    // Zoom keys must all be available, or all be unavailable.
+    bool noZoomRatio = !hasZoomRequestKey && !hasZoomResultKey && !hasZoomCharacteristicsKey &&
+                       !hasZoomRatioRange;
+    if (noZoomRatio) {
+        return;
+    }
+    bool hasZoomRatio =
+            hasZoomRequestKey && hasZoomResultKey && hasZoomCharacteristicsKey && hasZoomRatioRange;
+    ASSERT_TRUE(hasZoomRatio);
+
+    float minZoomRatio = entry.data.f[0];
+    float maxZoomRatio = entry.data.f[1];
+    constexpr float FLOATING_POINT_THRESHOLD = 0.00001f;
+    if (maxDigitalZoom > maxZoomRatio + FLOATING_POINT_THRESHOLD) {
+        ADD_FAILURE() << "Maximum digital zoom " << maxDigitalZoom
+                      << " is larger than maximum zoom ratio " << maxZoomRatio << " + threshold "
+                      << FLOATING_POINT_THRESHOLD << "!";
+    }
+    if (minZoomRatio > maxZoomRatio) {
+        ADD_FAILURE() << "Maximum zoom ratio is less than minimum zoom ratio!";
+    }
+    if (minZoomRatio > 1.0f) {
+        ADD_FAILURE() << "Minimum zoom ratio is more than 1.0!";
+    }
+    if (maxZoomRatio < 1.0f) {
+        ADD_FAILURE() << "Maximum zoom ratio is less than 1.0!";
+    }
+
+    // Make sure CROPPING_TYPE is CENTER_ONLY
+    retcode = find_camera_metadata_ro_entry(metadata, ANDROID_SCALER_CROPPING_TYPE, &entry);
+    if ((0 == retcode) && (entry.count == 1)) {
+        int8_t croppingType = entry.data.u8[0];
+        ASSERT_EQ(croppingType, ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY);
+    } else {
+        ADD_FAILURE() << "Get camera scalerCroppingType failed!";
+    }
+}
+
+void CameraAidlTest::verifyMonochromeCharacteristics(const CameraMetadata& chars) {
+    const camera_metadata_t* metadata = (camera_metadata_t*)chars.metadata.data();
+    Status rc = isMonochromeCamera(metadata);
+    if (Status::OPERATION_NOT_SUPPORTED == rc) {
+        return;
+    }
+    ASSERT_EQ(Status::OK, rc);
+
+    camera_metadata_ro_entry entry;
+    // Check capabilities
+    int retcode =
+            find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+    if ((0 == retcode) && (entry.count > 0)) {
+        ASSERT_EQ(std::find(entry.data.u8, entry.data.u8 + entry.count,
+                            ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING),
+                  entry.data.u8 + entry.count);
+    }
+
+    // Check Cfa
+    retcode = find_camera_metadata_ro_entry(metadata, ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,
+                                            &entry);
+    if ((0 == retcode) && (entry.count == 1)) {
+        ASSERT_TRUE(entry.data.i32[0] ==
+                            static_cast<int32_t>(
+                                    SensorInfoColorFilterArrangement::
+                                            ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO) ||
+                    entry.data.i32[0] ==
+                            static_cast<int32_t>(
+                                    SensorInfoColorFilterArrangement::
+                                            ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR));
+    }
+
+    // Check availableRequestKeys
+    retcode =
+            find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry);
+    if ((0 == retcode) && (entry.count > 0)) {
+        for (size_t i = 0; i < entry.count; i++) {
+            ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_MODE);
+            ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_TRANSFORM);
+            ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_GAINS);
+        }
+    } else {
+        ADD_FAILURE() << "Get camera availableRequestKeys failed!";
+    }
+
+    // Check availableResultKeys
+    retcode =
+            find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
+    if ((0 == retcode) && (entry.count > 0)) {
+        for (size_t i = 0; i < entry.count; i++) {
+            ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_GREEN_SPLIT);
+            ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_NEUTRAL_COLOR_POINT);
+            ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_MODE);
+            ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_TRANSFORM);
+            ASSERT_NE(entry.data.i32[i], ANDROID_COLOR_CORRECTION_GAINS);
+        }
+    } else {
+        ADD_FAILURE() << "Get camera availableResultKeys failed!";
+    }
+
+    // Check availableCharacteristicKeys
+    retcode = find_camera_metadata_ro_entry(metadata,
+                                            ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
+    if ((0 == retcode) && (entry.count > 0)) {
+        for (size_t i = 0; i < entry.count; i++) {
+            ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_REFERENCE_ILLUMINANT1);
+            ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_REFERENCE_ILLUMINANT2);
+            ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_CALIBRATION_TRANSFORM1);
+            ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_CALIBRATION_TRANSFORM2);
+            ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_COLOR_TRANSFORM1);
+            ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_COLOR_TRANSFORM2);
+            ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_FORWARD_MATRIX1);
+            ASSERT_NE(entry.data.i32[i], ANDROID_SENSOR_FORWARD_MATRIX2);
+        }
+    } else {
+        ADD_FAILURE() << "Get camera availableResultKeys failed!";
+    }
+
+    // Check blackLevelPattern
+    retcode = find_camera_metadata_ro_entry(metadata, ANDROID_SENSOR_BLACK_LEVEL_PATTERN, &entry);
+    if ((0 == retcode) && (entry.count > 0)) {
+        ASSERT_EQ(entry.count, 4);
+        for (size_t i = 1; i < entry.count; i++) {
+            ASSERT_EQ(entry.data.i32[i], entry.data.i32[0]);
+        }
+    }
+}
+
+void CameraAidlTest::verifyRecommendedConfigs(const CameraMetadata& chars) {
+    size_t CONFIG_ENTRY_SIZE = 5;
+    size_t CONFIG_ENTRY_TYPE_OFFSET = 3;
+    size_t CONFIG_ENTRY_BITFIELD_OFFSET = 4;
+    uint32_t maxPublicUsecase =
+            ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END_3_8;
+    uint32_t vendorUsecaseStart =
+            ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VENDOR_START;
+    uint32_t usecaseMask = (1 << vendorUsecaseStart) - 1;
+    usecaseMask &= ~((1 << maxPublicUsecase) - 1);
+
+    const camera_metadata_t* metadata =
+            reinterpret_cast<const camera_metadata_t*>(chars.metadata.data());
+
+    camera_metadata_ro_entry recommendedConfigsEntry, recommendedDepthConfigsEntry, ioMapEntry;
+    recommendedConfigsEntry.count = recommendedDepthConfigsEntry.count = ioMapEntry.count = 0;
+    int retCode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS,
+            &recommendedConfigsEntry);
+    int depthRetCode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS,
+            &recommendedDepthConfigsEntry);
+    int ioRetCode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP, &ioMapEntry);
+    if ((0 != retCode) && (0 != depthRetCode)) {
+        // In case both regular and depth recommended configurations are absent,
+        // I/O should be absent as well.
+        ASSERT_NE(ioRetCode, 0);
+        return;
+    }
+
+    camera_metadata_ro_entry availableKeysEntry;
+    retCode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &availableKeysEntry);
+    ASSERT_TRUE((0 == retCode) && (availableKeysEntry.count > 0));
+    std::vector<int32_t> availableKeys;
+    availableKeys.reserve(availableKeysEntry.count);
+    availableKeys.insert(availableKeys.end(), availableKeysEntry.data.i32,
+                         availableKeysEntry.data.i32 + availableKeysEntry.count);
+
+    if (recommendedConfigsEntry.count > 0) {
+        ASSERT_NE(std::find(availableKeys.begin(), availableKeys.end(),
+                            ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS),
+                  availableKeys.end());
+        ASSERT_EQ((recommendedConfigsEntry.count % CONFIG_ENTRY_SIZE), 0);
+        for (size_t i = 0; i < recommendedConfigsEntry.count; i += CONFIG_ENTRY_SIZE) {
+            int32_t entryType = recommendedConfigsEntry.data.i32[i + CONFIG_ENTRY_TYPE_OFFSET];
+            uint32_t bitfield = recommendedConfigsEntry.data.i32[i + CONFIG_ENTRY_BITFIELD_OFFSET];
+            ASSERT_TRUE((entryType == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) ||
+                        (entryType == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT));
+            ASSERT_TRUE((bitfield & usecaseMask) == 0);
+        }
+    }
+
+    if (recommendedDepthConfigsEntry.count > 0) {
+        ASSERT_NE(std::find(availableKeys.begin(), availableKeys.end(),
+                            ANDROID_DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS),
+                  availableKeys.end());
+        ASSERT_EQ((recommendedDepthConfigsEntry.count % CONFIG_ENTRY_SIZE), 0);
+        for (size_t i = 0; i < recommendedDepthConfigsEntry.count; i += CONFIG_ENTRY_SIZE) {
+            int32_t entryType = recommendedDepthConfigsEntry.data.i32[i + CONFIG_ENTRY_TYPE_OFFSET];
+            uint32_t bitfield =
+                    recommendedDepthConfigsEntry.data.i32[i + CONFIG_ENTRY_BITFIELD_OFFSET];
+            ASSERT_TRUE((entryType == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) ||
+                        (entryType == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT));
+            ASSERT_TRUE((bitfield & usecaseMask) == 0);
+        }
+
+        if (recommendedConfigsEntry.count == 0) {
+            // In case regular recommended configurations are absent but suggested depth
+            // configurations are present, I/O should be absent.
+            ASSERT_NE(ioRetCode, 0);
+        }
+    }
+
+    if ((ioRetCode == 0) && (ioMapEntry.count > 0)) {
+        ASSERT_NE(std::find(availableKeys.begin(), availableKeys.end(),
+                            ANDROID_SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP),
+                  availableKeys.end());
+        ASSERT_EQ(isZSLModeAvailable(metadata), Status::OK);
+    }
+}
+
+// Check whether ZSL is available using the static camera
+// characteristics.
+Status CameraAidlTest::isZSLModeAvailable(const camera_metadata_t* staticMeta) {
+    if (Status::OK == isZSLModeAvailable(staticMeta, PRIV_REPROCESS)) {
+        return Status::OK;
+    } else {
+        return isZSLModeAvailable(staticMeta, YUV_REPROCESS);
+    }
+}
+
+Status CameraAidlTest::isZSLModeAvailable(const camera_metadata_t* staticMeta,
+                                          ReprocessType reprocType) {
+    Status ret = Status::OPERATION_NOT_SUPPORTED;
+    if (nullptr == staticMeta) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                           &entry);
+    if (0 != rc) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    for (size_t i = 0; i < entry.count; i++) {
+        if ((reprocType == PRIV_REPROCESS &&
+             ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING == entry.data.u8[i]) ||
+            (reprocType == YUV_REPROCESS &&
+             ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING == entry.data.u8[i])) {
+            ret = Status::OK;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+// Verify logical or ultra high resolution camera static metadata
+void CameraAidlTest::verifyLogicalOrUltraHighResCameraMetadata(
+        const std::string& cameraName, const std::shared_ptr<ICameraDevice>& device,
+        const CameraMetadata& chars, const std::vector<std::string>& deviceNames) {
+    const camera_metadata_t* metadata =
+            reinterpret_cast<const camera_metadata_t*>(chars.metadata.data());
+    ASSERT_NE(nullptr, metadata);
+    SystemCameraKind systemCameraKind = SystemCameraKind::PUBLIC;
+    Status retStatus = getSystemCameraKind(metadata, &systemCameraKind);
+    ASSERT_EQ(retStatus, Status::OK);
+    Status rc = isLogicalMultiCamera(metadata);
+    ASSERT_TRUE(Status::OK == rc || Status::OPERATION_NOT_SUPPORTED == rc);
+    bool isMultiCamera = (Status::OK == rc);
+    bool isUltraHighResCamera = isUltraHighResolution(metadata);
+    if (!isMultiCamera && !isUltraHighResCamera) {
+        return;
+    }
+
+    camera_metadata_ro_entry entry;
+    int retcode = find_camera_metadata_ro_entry(metadata, ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+    bool hasZoomRatioRange = (0 == retcode && entry.count == 2);
+    retcode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
+    bool hasHalBufferManager =
+            (0 == retcode && 1 == entry.count &&
+             entry.data.i32[0] == ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+    retcode = find_camera_metadata_ro_entry(
+            metadata, ANDROID_SCALER_MULTI_RESOLUTION_STREAM_SUPPORTED, &entry);
+    bool multiResolutionStreamSupported =
+            (0 == retcode && 1 == entry.count &&
+             entry.data.u8[0] == ANDROID_SCALER_MULTI_RESOLUTION_STREAM_SUPPORTED_TRUE);
+    if (multiResolutionStreamSupported) {
+        ASSERT_TRUE(hasHalBufferManager);
+    }
+
+    std::string version, cameraId;
+    ASSERT_TRUE(::matchDeviceName(cameraName, mProviderType, &version, &cameraId));
+    std::unordered_set<std::string> physicalIds;
+    rc = getPhysicalCameraIds(metadata, &physicalIds);
+    ASSERT_TRUE(isUltraHighResCamera || Status::OK == rc);
+    for (const auto& physicalId : physicalIds) {
+        ASSERT_NE(physicalId, cameraId);
+    }
+    if (physicalIds.size() == 0) {
+        ASSERT_TRUE(isUltraHighResCamera && !isMultiCamera);
+        physicalIds.insert(cameraId);
+    }
+
+    std::unordered_set<int32_t> physicalRequestKeyIDs;
+    rc = getSupportedKeys(const_cast<camera_metadata_t*>(metadata),
+                          ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS,
+                          &physicalRequestKeyIDs);
+    ASSERT_TRUE(Status::OK == rc);
+    bool hasTestPatternPhysicalRequestKey =
+            physicalRequestKeyIDs.find(ANDROID_SENSOR_TEST_PATTERN_MODE) !=
+            physicalRequestKeyIDs.end();
+    std::unordered_set<int32_t> privacyTestPatternModes;
+    getPrivacyTestPatternModes(metadata, &privacyTestPatternModes);
+
+    // Map from image format to number of multi-resolution sizes for that format
+    std::unordered_map<int32_t, size_t> multiResOutputFormatCounterMap;
+    std::unordered_map<int32_t, size_t> multiResInputFormatCounterMap;
+    for (const auto& physicalId : physicalIds) {
+        bool isPublicId = false;
+        std::string fullPublicId;
+        SystemCameraKind physSystemCameraKind = SystemCameraKind::PUBLIC;
+        for (auto& deviceName : deviceNames) {
+            std::string publicVersion, publicId;
+            ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, &publicVersion, &publicId));
+            if (physicalId == publicId) {
+                isPublicId = true;
+                fullPublicId = deviceName;
+                break;
+            }
+        }
+
+        camera_metadata_ro_entry physicalMultiResStreamConfigs;
+        camera_metadata_ro_entry physicalStreamConfigs;
+        camera_metadata_ro_entry physicalMaxResolutionStreamConfigs;
+        bool isUltraHighRes = false;
+        std::unordered_set<int32_t> subCameraPrivacyTestPatterns;
+        if (isPublicId) {
+            std::shared_ptr<ICameraDevice> subDevice;
+            ndk::ScopedAStatus ret = mProvider->getCameraDeviceInterface(fullPublicId, &subDevice);
+            ASSERT_TRUE(ret.isOk());
+            ASSERT_NE(subDevice, nullptr);
+
+            CameraMetadata subDeviceChars;
+            ret = subDevice->getCameraCharacteristics(&subDeviceChars);
+            ASSERT_TRUE(ret.isOk());
+
+            const camera_metadata_t* staticMetadata =
+                    reinterpret_cast<const camera_metadata_t*>(subDeviceChars.metadata.data());
+            retStatus = getSystemCameraKind(staticMetadata, &physSystemCameraKind);
+            ASSERT_EQ(retStatus, Status::OK);
+
+            // Make sure that the system camera kind of a non-hidden
+            // physical cameras is the same as the logical camera associated
+            // with it.
+            ASSERT_EQ(physSystemCameraKind, systemCameraKind);
+            retcode = find_camera_metadata_ro_entry(staticMetadata,
+                                                    ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+            bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2);
+            ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange);
+
+            getMultiResolutionStreamConfigurations(
+                    &physicalMultiResStreamConfigs, &physicalStreamConfigs,
+                    &physicalMaxResolutionStreamConfigs, staticMetadata);
+            isUltraHighRes = isUltraHighResolution(staticMetadata);
+
+            getPrivacyTestPatternModes(staticMetadata, &subCameraPrivacyTestPatterns);
+        } else {
+            // Check camera characteristics for hidden camera id
+            CameraMetadata physChars;
+            ndk::ScopedAStatus ret =
+                    device->getPhysicalCameraCharacteristics(physicalId, &physChars);
+            ASSERT_TRUE(ret.isOk());
+            verifyCameraCharacteristics(physChars);
+            verifyMonochromeCharacteristics(physChars);
+
+            auto staticMetadata = (const camera_metadata_t*)physChars.metadata.data();
+            retcode = find_camera_metadata_ro_entry(staticMetadata,
+                                                    ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+            bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2);
+            ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange);
+
+            getMultiResolutionStreamConfigurations(
+                    &physicalMultiResStreamConfigs, &physicalStreamConfigs,
+                    &physicalMaxResolutionStreamConfigs, staticMetadata);
+            isUltraHighRes = isUltraHighResolution(staticMetadata);
+            getPrivacyTestPatternModes(staticMetadata, &subCameraPrivacyTestPatterns);
+
+            // Check calling getCameraDeviceInterface_V3_x() on hidden camera id returns
+            // ILLEGAL_ARGUMENT.
+            std::stringstream s;
+            s << "device@" << version << "/" << mProviderType << "/" << physicalId;
+            std::string fullPhysicalId(s.str());
+            std::shared_ptr<ICameraDevice> subDevice;
+            ret = mProvider->getCameraDeviceInterface(fullPhysicalId, &subDevice);
+            ASSERT_TRUE(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT) ==
+                        ret.getServiceSpecificError());
+            ASSERT_EQ(subDevice, nullptr);
+        }
+
+        if (hasTestPatternPhysicalRequestKey) {
+            ASSERT_TRUE(privacyTestPatternModes == subCameraPrivacyTestPatterns);
+        }
+
+        if (physicalMultiResStreamConfigs.count > 0) {
+            ASSERT_EQ(physicalMultiResStreamConfigs.count % 4, 0);
+
+            // Each supported size must be max size for that format,
+            for (size_t i = 0; i < physicalMultiResStreamConfigs.count / 4; i++) {
+                int32_t multiResFormat = physicalMultiResStreamConfigs.data.i32[i * 4];
+                int32_t multiResWidth = physicalMultiResStreamConfigs.data.i32[i * 4 + 1];
+                int32_t multiResHeight = physicalMultiResStreamConfigs.data.i32[i * 4 + 2];
+                int32_t multiResInput = physicalMultiResStreamConfigs.data.i32[i * 4 + 3];
+
+                // Check if the resolution is the max resolution in stream
+                // configuration map
+                bool supported = false;
+                bool isMaxSize = true;
+                for (size_t j = 0; j < physicalStreamConfigs.count / 4; j++) {
+                    int32_t format = physicalStreamConfigs.data.i32[j * 4];
+                    int32_t width = physicalStreamConfigs.data.i32[j * 4 + 1];
+                    int32_t height = physicalStreamConfigs.data.i32[j * 4 + 2];
+                    int32_t input = physicalStreamConfigs.data.i32[j * 4 + 3];
+                    if (format == multiResFormat && input == multiResInput) {
+                        if (width == multiResWidth && height == multiResHeight) {
+                            supported = true;
+                        } else if (width * height > multiResWidth * multiResHeight) {
+                            isMaxSize = false;
+                        }
+                    }
+                }
+                // Check if the resolution is the max resolution in max
+                // resolution stream configuration map
+                bool supportedUltraHighRes = false;
+                bool isUltraHighResMaxSize = true;
+                for (size_t j = 0; j < physicalMaxResolutionStreamConfigs.count / 4; j++) {
+                    int32_t format = physicalMaxResolutionStreamConfigs.data.i32[j * 4];
+                    int32_t width = physicalMaxResolutionStreamConfigs.data.i32[j * 4 + 1];
+                    int32_t height = physicalMaxResolutionStreamConfigs.data.i32[j * 4 + 2];
+                    int32_t input = physicalMaxResolutionStreamConfigs.data.i32[j * 4 + 3];
+                    if (format == multiResFormat && input == multiResInput) {
+                        if (width == multiResWidth && height == multiResHeight) {
+                            supportedUltraHighRes = true;
+                        } else if (width * height > multiResWidth * multiResHeight) {
+                            isUltraHighResMaxSize = false;
+                        }
+                    }
+                }
+
+                if (isUltraHighRes) {
+                    // For ultra high resolution camera, the configuration must
+                    // be the maximum size in stream configuration map, or max
+                    // resolution stream configuration map
+                    ASSERT_TRUE((supported && isMaxSize) ||
+                                (supportedUltraHighRes && isUltraHighResMaxSize));
+                } else {
+                    // The configuration must be the maximum size in stream
+                    // configuration map
+                    ASSERT_TRUE(supported && isMaxSize);
+                    ASSERT_FALSE(supportedUltraHighRes);
+                }
+
+                // Increment the counter for the configuration's format.
+                auto& formatCounterMap = multiResInput ? multiResInputFormatCounterMap
+                                                       : multiResOutputFormatCounterMap;
+                if (formatCounterMap.count(multiResFormat) == 0) {
+                    formatCounterMap[multiResFormat] = 1;
+                } else {
+                    formatCounterMap[multiResFormat]++;
+                }
+            }
+
+            // There must be no duplicates
+            for (size_t i = 0; i < physicalMultiResStreamConfigs.count / 4 - 1; i++) {
+                for (size_t j = i + 1; j < physicalMultiResStreamConfigs.count / 4; j++) {
+                    // Input/output doesn't match
+                    if (physicalMultiResStreamConfigs.data.i32[i * 4 + 3] !=
+                        physicalMultiResStreamConfigs.data.i32[j * 4 + 3]) {
+                        continue;
+                    }
+                    // Format doesn't match
+                    if (physicalMultiResStreamConfigs.data.i32[i * 4] !=
+                        physicalMultiResStreamConfigs.data.i32[j * 4]) {
+                        continue;
+                    }
+                    // Width doesn't match
+                    if (physicalMultiResStreamConfigs.data.i32[i * 4 + 1] !=
+                        physicalMultiResStreamConfigs.data.i32[j * 4 + 1]) {
+                        continue;
+                    }
+                    // Height doesn't match
+                    if (physicalMultiResStreamConfigs.data.i32[i * 4 + 2] !=
+                        physicalMultiResStreamConfigs.data.i32[j * 4 + 2]) {
+                        continue;
+                    }
+                    // input/output, format, width, and height all match
+                    ADD_FAILURE();
+                }
+            }
+        }
+    }
+
+    // If a multi-resolution stream is supported, there must be at least one
+    // format with more than one resolutions
+    if (multiResolutionStreamSupported) {
+        size_t numMultiResFormats = 0;
+        for (const auto& [format, sizeCount] : multiResOutputFormatCounterMap) {
+            if (sizeCount >= 2) {
+                numMultiResFormats++;
+            }
+        }
+        for (const auto& [format, sizeCount] : multiResInputFormatCounterMap) {
+            if (sizeCount >= 2) {
+                numMultiResFormats++;
+
+                // If multi-resolution reprocessing is supported, the logical
+                // camera or ultra-high resolution sensor camera must support
+                // the corresponding reprocessing capability.
+                if (format == static_cast<uint32_t>(PixelFormat::IMPLEMENTATION_DEFINED)) {
+                    ASSERT_EQ(isZSLModeAvailable(metadata, PRIV_REPROCESS), Status::OK);
+                } else if (format == static_cast<int32_t>(PixelFormat::YCBCR_420_888)) {
+                    ASSERT_EQ(isZSLModeAvailable(metadata, YUV_REPROCESS), Status::OK);
+                }
+            }
+        }
+        ASSERT_GT(numMultiResFormats, 0);
+    }
+
+    // Make sure ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID is available in
+    // result keys.
+    if (isMultiCamera) {
+        retcode = find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,
+                                                &entry);
+        if ((0 == retcode) && (entry.count > 0)) {
+            ASSERT_NE(std::find(entry.data.i32, entry.data.i32 + entry.count,
+                                static_cast<int32_t>(
+                                        CameraMetadataTag::
+                                                ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID)),
+                      entry.data.i32 + entry.count);
+        } else {
+            ADD_FAILURE() << "Get camera availableResultKeys failed!";
+        }
+    }
+}
+
+bool CameraAidlTest::isUltraHighResolution(const camera_metadata_t* staticMeta) {
+    camera_metadata_ro_entry scalerEntry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                           &scalerEntry);
+    if (rc == 0) {
+        for (uint32_t i = 0; i < scalerEntry.count; i++) {
+            if (scalerEntry.data.u8[i] ==
+                ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+Status CameraAidlTest::getSupportedKeys(camera_metadata_t* staticMeta, uint32_t tagId,
+                                        std::unordered_set<int32_t>* requestIDs) {
+    if ((nullptr == staticMeta) || (nullptr == requestIDs)) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, tagId, &entry);
+    if ((0 != rc) || (entry.count == 0)) {
+        return Status::OK;
+    }
+
+    requestIDs->insert(entry.data.i32, entry.data.i32 + entry.count);
+
+    return Status::OK;
+}
+
+void CameraAidlTest::getPrivacyTestPatternModes(
+        const camera_metadata_t* staticMetadata,
+        std::unordered_set<int32_t>* privacyTestPatternModes) {
+    ASSERT_NE(staticMetadata, nullptr);
+    ASSERT_NE(privacyTestPatternModes, nullptr);
+
+    camera_metadata_ro_entry entry;
+    int retcode = find_camera_metadata_ro_entry(
+            staticMetadata, ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES, &entry);
+    ASSERT_TRUE(0 == retcode);
+
+    for (auto i = 0; i < entry.count; i++) {
+        if (entry.data.i32[i] == ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR ||
+            entry.data.i32[i] == ANDROID_SENSOR_TEST_PATTERN_MODE_BLACK) {
+            privacyTestPatternModes->insert(entry.data.i32[i]);
+        }
+    }
+}
+
+void CameraAidlTest::getMultiResolutionStreamConfigurations(
+        camera_metadata_ro_entry* multiResStreamConfigs, camera_metadata_ro_entry* streamConfigs,
+        camera_metadata_ro_entry* maxResolutionStreamConfigs,
+        const camera_metadata_t* staticMetadata) {
+    ASSERT_NE(multiResStreamConfigs, nullptr);
+    ASSERT_NE(streamConfigs, nullptr);
+    ASSERT_NE(maxResolutionStreamConfigs, nullptr);
+    ASSERT_NE(staticMetadata, nullptr);
+
+    int retcode = find_camera_metadata_ro_entry(
+            staticMetadata, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, streamConfigs);
+    ASSERT_TRUE(0 == retcode);
+    retcode = find_camera_metadata_ro_entry(
+            staticMetadata, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+            maxResolutionStreamConfigs);
+    ASSERT_TRUE(-ENOENT == retcode || 0 == retcode);
+    retcode = find_camera_metadata_ro_entry(
+            staticMetadata, ANDROID_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS,
+            multiResStreamConfigs);
+    ASSERT_TRUE(-ENOENT == retcode || 0 == retcode);
+}
+
+bool CameraAidlTest::isTorchSupported(const camera_metadata_t* staticMeta) {
+    camera_metadata_ro_entry torchEntry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_FLASH_INFO_AVAILABLE, &torchEntry);
+    if (rc != 0) {
+        ALOGI("isTorchSupported: Failed to find entry for ANDROID_FLASH_INFO_AVAILABLE");
+        return false;
+    }
+    if (torchEntry.count == 1 && !torchEntry.data.u8[0]) {
+        ALOGI("isTorchSupported: Torch not supported");
+        return false;
+    }
+    ALOGI("isTorchSupported: Torch supported");
+    return true;
+}
+
+bool CameraAidlTest::isTorchStrengthControlSupported(const camera_metadata_t* staticMeta) {
+    int32_t maxLevel = 0;
+    camera_metadata_ro_entry maxEntry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL,
+                                           &maxEntry);
+    if (rc != 0) {
+        ALOGI("isTorchStrengthControlSupported: Failed to find entry for "
+              "ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL");
+        return false;
+    }
+
+    maxLevel = *maxEntry.data.i32;
+    if (maxLevel > 1) {
+        ALOGI("isTorchStrengthControlSupported: Torch strength control supported.");
+        return true;
+    }
+    ALOGI("isTorchStrengthControlSupported: Torch strength control not supported.");
+    return false;
+}
+
+void CameraAidlTest::verifyRequestTemplate(const camera_metadata_t* metadata,
+                                           RequestTemplate requestTemplate) {
+    ASSERT_NE(nullptr, metadata);
+    size_t entryCount = get_camera_metadata_entry_count(metadata);
+    ALOGI("template %u metadata entry count is %zu", (int32_t)requestTemplate, entryCount);
+    // TODO: we can do better than 0 here. Need to check how many required
+    // request keys we've defined for each template
+    ASSERT_GT(entryCount, 0u);
+
+    // Check zoomRatio
+    camera_metadata_ro_entry zoomRatioEntry;
+    int foundZoomRatio =
+            find_camera_metadata_ro_entry(metadata, ANDROID_CONTROL_ZOOM_RATIO, &zoomRatioEntry);
+    if (foundZoomRatio == 0) {
+        ASSERT_EQ(zoomRatioEntry.count, 1);
+        ASSERT_EQ(zoomRatioEntry.data.f[0], 1.0f);
+    }
+}
+
+void CameraAidlTest::openEmptyDeviceSession(const std::string& name,
+                                            const std::shared_ptr<ICameraProvider>& provider,
+                                            std::shared_ptr<ICameraDeviceSession>* session,
+                                            CameraMetadata* staticMeta,
+                                            std::shared_ptr<ICameraDevice>* device) {
+    ASSERT_NE(nullptr, session);
+    ASSERT_NE(nullptr, staticMeta);
+    ASSERT_NE(nullptr, device);
+
+    ALOGI("configureStreams: Testing camera device %s", name.c_str());
+    ndk::ScopedAStatus ret = provider->getCameraDeviceInterface(name, device);
+    ALOGI("getCameraDeviceInterface returns status:%d:%d", ret.getExceptionCode(),
+          ret.getServiceSpecificError());
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_NE(device, nullptr);
+
+    std::shared_ptr<EmptyDeviceCb> cb = ndk::SharedRefBase::make<EmptyDeviceCb>();
+    ret = (*device)->open(cb, session);
+    ALOGI("device::open returns status:%d:%d", ret.getExceptionCode(),
+          ret.getServiceSpecificError());
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_NE(*session, nullptr);
+
+    ret = (*device)->getCameraCharacteristics(staticMeta);
+    ASSERT_TRUE(ret.isOk());
+}
+
+void CameraAidlTest::openEmptyInjectionSession(const std::string& name,
+                                               const std::shared_ptr<ICameraProvider>& provider,
+                                               std::shared_ptr<ICameraInjectionSession>* session,
+                                               CameraMetadata* metadata,
+                                               std::shared_ptr<ICameraDevice>* device) {
+    ASSERT_NE(nullptr, session);
+    ASSERT_NE(nullptr, metadata);
+    ASSERT_NE(nullptr, device);
+
+    ALOGI("openEmptyInjectionSession: Testing camera device %s", name.c_str());
+    ndk::ScopedAStatus ret = provider->getCameraDeviceInterface(name, device);
+    ALOGI("openEmptyInjectionSession: getCameraDeviceInterface returns status:%d:%d",
+          ret.getExceptionCode(), ret.getServiceSpecificError());
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_NE(*device, nullptr);
+
+    std::shared_ptr<EmptyDeviceCb> cb = ndk::SharedRefBase::make<EmptyDeviceCb>();
+    ret = (*device)->openInjectionSession(cb, session);
+    ALOGI("device::openInjectionSession returns status:%d:%d", ret.getExceptionCode(),
+          ret.getServiceSpecificError());
+
+    if (static_cast<Status>(ret.getServiceSpecificError()) == Status::OPERATION_NOT_SUPPORTED &&
+        *session == nullptr) {
+        return;  // Injection Session not supported. Callee will receive nullptr in *session
+    }
+
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_NE(*session, nullptr);
+
+    ret = (*device)->getCameraCharacteristics(metadata);
+    ASSERT_TRUE(ret.isOk());
+}
+
+Status CameraAidlTest::getJpegBufferSize(camera_metadata_t* staticMeta, int32_t* outBufSize) {
+    if (nullptr == staticMeta || nullptr == outBufSize) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_JPEG_MAX_SIZE, &entry);
+    if ((0 != rc) || (1 != entry.count)) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    *outBufSize = entry.data.i32[0];
+    return Status::OK;
+}
+
+Dataspace CameraAidlTest::getDataspace(PixelFormat format) {
+    switch (format) {
+        case PixelFormat::BLOB:
+            return Dataspace::JFIF;
+        case PixelFormat::Y16:
+            return Dataspace::DEPTH;
+        case PixelFormat::RAW16:
+        case PixelFormat::RAW_OPAQUE:
+        case PixelFormat::RAW10:
+        case PixelFormat::RAW12:
+            return Dataspace::ARBITRARY;
+        default:
+            return Dataspace::UNKNOWN;
+    }
+}
+
+void CameraAidlTest::createStreamConfiguration(std::vector<Stream>& streams,
+                                               StreamConfigurationMode configMode,
+                                               StreamConfiguration* config,
+                                               int32_t jpegBufferSize) {
+    ASSERT_NE(nullptr, config);
+
+    for (auto& stream : streams) {
+        stream.bufferSize =
+                (stream.format == PixelFormat::BLOB && stream.dataSpace == Dataspace::JFIF)
+                        ? jpegBufferSize
+                        : 0;
+    }
+
+    // Caller is responsible to fill in non-zero config->streamConfigCounter after this returns
+    config->streams = streams;
+    config->operationMode = configMode;
+    config->multiResolutionInputImage = false;
+}
+
+void CameraAidlTest::verifyStreamCombination(const std::shared_ptr<ICameraDevice>& device,
+                                             const StreamConfiguration& config, bool expectedStatus,
+                                             bool expectStreamCombQuery) {
+    if (device != nullptr) {
+        bool streamCombinationSupported;
+        ScopedAStatus ret =
+                device->isStreamCombinationSupported(config, &streamCombinationSupported);
+        // TODO: Check is unsupported operation is correct.
+        ASSERT_TRUE(ret.isOk() ||
+                    (expectStreamCombQuery && ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION));
+        if (ret.isOk()) {
+            ASSERT_EQ(expectedStatus, streamCombinationSupported);
+        }
+    }
+}
+
+std::vector<ConcurrentCameraIdCombination> CameraAidlTest::getConcurrentDeviceCombinations(
+        std::shared_ptr<ICameraProvider>& provider) {
+    std::vector<ConcurrentCameraIdCombination> combinations;
+    ndk::ScopedAStatus ret = provider->getConcurrentCameraIds(&combinations);
+    if (!ret.isOk()) {
+        ADD_FAILURE();
+    }
+
+    return combinations;
+}
+
+Status CameraAidlTest::getMandatoryConcurrentStreams(const camera_metadata_t* staticMeta,
+                                                     std::vector<AvailableStream>* outputStreams) {
+    if (nullptr == staticMeta || nullptr == outputStreams) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (isDepthOnly(staticMeta)) {
+        Size y16MaxSize(640, 480);
+        Size maxAvailableY16Size;
+        getMaxOutputSizeForFormat(staticMeta, PixelFormat::Y16, &maxAvailableY16Size);
+        Size y16ChosenSize = getMinSize(y16MaxSize, maxAvailableY16Size);
+        AvailableStream y16Stream = {.width = y16ChosenSize.width,
+                                     .height = y16ChosenSize.height,
+                                     .format = static_cast<int32_t>(PixelFormat::Y16)};
+        outputStreams->push_back(y16Stream);
+        return Status::OK;
+    }
+
+    Size yuvMaxSize(1280, 720);
+    Size jpegMaxSize(1920, 1440);
+    Size maxAvailableYuvSize;
+    Size maxAvailableJpegSize;
+    getMaxOutputSizeForFormat(staticMeta, PixelFormat::YCBCR_420_888, &maxAvailableYuvSize);
+    getMaxOutputSizeForFormat(staticMeta, PixelFormat::BLOB, &maxAvailableJpegSize);
+    Size yuvChosenSize = getMinSize(yuvMaxSize, maxAvailableYuvSize);
+    Size jpegChosenSize = getMinSize(jpegMaxSize, maxAvailableJpegSize);
+
+    AvailableStream yuvStream = {.width = yuvChosenSize.width,
+                                 .height = yuvChosenSize.height,
+                                 .format = static_cast<int32_t>(PixelFormat::YCBCR_420_888)};
+
+    AvailableStream jpegStream = {.width = jpegChosenSize.width,
+                                  .height = jpegChosenSize.height,
+                                  .format = static_cast<int32_t>(PixelFormat::BLOB)};
+    outputStreams->push_back(yuvStream);
+    outputStreams->push_back(jpegStream);
+
+    return Status::OK;
+}
+
+bool CameraAidlTest::isDepthOnly(const camera_metadata_t* staticMeta) {
+    camera_metadata_ro_entry scalerEntry;
+    camera_metadata_ro_entry depthEntry;
+
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                           &scalerEntry);
+    if (rc == 0) {
+        for (uint32_t i = 0; i < scalerEntry.count; i++) {
+            if (scalerEntry.data.u8[i] ==
+                ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) {
+                return false;
+            }
+        }
+    }
+
+    for (uint32_t i = 0; i < scalerEntry.count; i++) {
+        if (scalerEntry.data.u8[i] == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT) {
+            rc = find_camera_metadata_ro_entry(
+                    staticMeta, ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, &depthEntry);
+            size_t idx = 0;
+            if (rc == 0 && depthEntry.data.i32[idx] == static_cast<int32_t>(PixelFormat::Y16)) {
+                // only Depth16 format is supported now
+                return true;
+            }
+            break;
+        }
+    }
+
+    return false;
+}
+
+Status CameraAidlTest::getMaxOutputSizeForFormat(const camera_metadata_t* staticMeta,
+                                                 PixelFormat format, Size* size,
+                                                 bool maxResolution) {
+    std::vector<AvailableStream> outputStreams;
+    if (size == nullptr ||
+        getAvailableOutputStreams(staticMeta, outputStreams,
+                                  /*threshold*/ nullptr, maxResolution) != Status::OK) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+    Size maxSize;
+    bool found = false;
+    for (auto& outputStream : outputStreams) {
+        if (static_cast<int32_t>(format) == outputStream.format &&
+            (outputStream.width * outputStream.height > maxSize.width * maxSize.height)) {
+            maxSize.width = outputStream.width;
+            maxSize.height = outputStream.height;
+            found = true;
+        }
+    }
+    if (!found) {
+        ALOGE("%s :chosen format %d not found", __FUNCTION__, static_cast<int32_t>(format));
+        return Status::ILLEGAL_ARGUMENT;
+    }
+    *size = maxSize;
+    return Status::OK;
+}
+
+Size CameraAidlTest::getMinSize(Size a, Size b) {
+    if (a.width * a.height < b.width * b.height) {
+        return a;
+    }
+    return b;
+}
+
+Status CameraAidlTest::getZSLInputOutputMap(camera_metadata_t* staticMeta,
+                                            std::vector<AvailableZSLInputOutput>& inputOutputMap) {
+    if (nullptr == staticMeta) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(
+            staticMeta, ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP, &entry);
+    if ((0 != rc) || (0 >= entry.count)) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    const int32_t* contents = &entry.data.i32[0];
+    for (size_t i = 0; i < entry.count;) {
+        int32_t inputFormat = contents[i++];
+        int32_t length = contents[i++];
+        for (int32_t j = 0; j < length; j++) {
+            int32_t outputFormat = contents[i + j];
+            AvailableZSLInputOutput zslEntry = {inputFormat, outputFormat};
+            inputOutputMap.push_back(zslEntry);
+        }
+        i += length;
+    }
+
+    return Status::OK;
+}
+
+Status CameraAidlTest::findLargestSize(const std::vector<AvailableStream>& streamSizes,
+                                       int32_t format, AvailableStream& result) {
+    result = {0, 0, 0};
+    for (auto& iter : streamSizes) {
+        if (format == iter.format) {
+            if ((result.width * result.height) < (iter.width * iter.height)) {
+                result = iter;
+            }
+        }
+    }
+
+    return (result.format == format) ? Status::OK : Status::ILLEGAL_ARGUMENT;
+}
+
+void CameraAidlTest::constructFilteredSettings(
+        const std::shared_ptr<ICameraDeviceSession>& session,
+        const std::unordered_set<int32_t>& availableKeys, RequestTemplate reqTemplate,
+        android::hardware::camera::common::V1_0::helper::CameraMetadata* defaultSettings,
+        android::hardware::camera::common::V1_0::helper::CameraMetadata* filteredSettings) {
+    ASSERT_NE(defaultSettings, nullptr);
+    ASSERT_NE(filteredSettings, nullptr);
+
+    CameraMetadata req;
+    auto ret = session->constructDefaultRequestSettings(reqTemplate, &req);
+    ASSERT_TRUE(ret.isOk());
+
+    const camera_metadata_t* metadata =
+            clone_camera_metadata(reinterpret_cast<const camera_metadata_t*>(req.metadata.data()));
+    size_t expectedSize = req.metadata.size();
+    int result = validate_camera_metadata_structure(metadata, &expectedSize);
+    ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+
+    size_t entryCount = get_camera_metadata_entry_count(metadata);
+    ASSERT_GT(entryCount, 0u);
+    *defaultSettings = metadata;
+
+    const android::hardware::camera::common::V1_0::helper::CameraMetadata& constSettings =
+            *defaultSettings;
+    for (const auto& keyIt : availableKeys) {
+        camera_metadata_ro_entry entry = constSettings.find(keyIt);
+        if (entry.count > 0) {
+            filteredSettings->update(entry);
+        }
+    }
+}
+
+void CameraAidlTest::verifySessionReconfigurationQuery(
+        const std::shared_ptr<ICameraDeviceSession>& session, camera_metadata* oldSessionParams,
+        camera_metadata* newSessionParams) {
+    ASSERT_NE(nullptr, session);
+    ASSERT_NE(nullptr, oldSessionParams);
+    ASSERT_NE(nullptr, newSessionParams);
+
+    std::vector<uint8_t> oldParams =
+            std::vector(reinterpret_cast<uint8_t*>(oldSessionParams),
+                        reinterpret_cast<uint8_t*>(oldSessionParams) +
+                                get_camera_metadata_size(oldSessionParams));
+    CameraMetadata oldMetadata = {oldParams};
+
+    std::vector<uint8_t> newParams =
+            std::vector(reinterpret_cast<uint8_t*>(newSessionParams),
+                        reinterpret_cast<uint8_t*>(newSessionParams) +
+                                get_camera_metadata_size(newSessionParams));
+    CameraMetadata newMetadata = {newParams};
+
+    bool reconfigReq;
+    ndk::ScopedAStatus ret =
+            session->isReconfigurationRequired(oldMetadata, newMetadata, &reconfigReq);
+    ASSERT_TRUE(ret.isOk() || static_cast<Status>(ret.getServiceSpecificError()) ==
+                                      Status::OPERATION_NOT_SUPPORTED);
+}
+
+Status CameraAidlTest::isConstrainedModeAvailable(camera_metadata_t* staticMeta) {
+    Status ret = Status::OPERATION_NOT_SUPPORTED;
+    if (nullptr == staticMeta) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                           &entry);
+    if (0 != rc) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    for (size_t i = 0; i < entry.count; i++) {
+        if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO ==
+            entry.data.u8[i]) {
+            ret = Status::OK;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+Status CameraAidlTest::pickConstrainedModeSize(camera_metadata_t* staticMeta,
+                                               AvailableStream& hfrStream) {
+    if (nullptr == staticMeta) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(
+            staticMeta, ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS, &entry);
+    if (0 != rc) {
+        return Status::OPERATION_NOT_SUPPORTED;
+    } else if (0 != (entry.count % 5)) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    hfrStream = {0, 0, static_cast<uint32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+    for (size_t i = 0; i < entry.count; i += 5) {
+        int32_t w = entry.data.i32[i];
+        int32_t h = entry.data.i32[i + 1];
+        if ((hfrStream.width * hfrStream.height) < (w * h)) {
+            hfrStream.width = w;
+            hfrStream.height = h;
+        }
+    }
+
+    return Status::OK;
+}
+
+void CameraAidlTest::processCaptureRequestInternal(uint64_t bufferUsage,
+                                                   RequestTemplate reqTemplate,
+                                                   bool useSecureOnlyCameras) {
+    std::vector<std::string> cameraDeviceNames =
+            getCameraDeviceNames(mProvider, useSecureOnlyCameras);
+    AvailableStream streamThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                       static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+    int64_t bufferId = 1;
+    int32_t frameNumber = 1;
+    CameraMetadata settings;
+
+    for (const auto& name : cameraDeviceNames) {
+        Stream testStream;
+        std::vector<HalStream> halStreams;
+        std::shared_ptr<ICameraDeviceSession> session;
+        std::shared_ptr<DeviceCb> cb;
+        bool supportsPartialResults = false;
+        bool useHalBufManager = false;
+        int32_t partialResultCount = 0;
+        configureSingleStream(name, mProvider, &streamThreshold, bufferUsage, reqTemplate,
+                              &session /*out*/, &testStream /*out*/, &halStreams /*out*/,
+                              &supportsPartialResults /*out*/, &partialResultCount /*out*/,
+                              &useHalBufManager /*out*/, &cb /*out*/);
+
+        ASSERT_NE(session, nullptr);
+        ASSERT_NE(cb, nullptr);
+        ASSERT_FALSE(halStreams.empty());
+
+        std::shared_ptr<ResultMetadataQueue> resultQueue;
+        ::aidl::android::hardware::common::fmq::MQDescriptor<
+                int8_t, aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+                descriptor;
+        ndk::ScopedAStatus ret = session->getCaptureResultMetadataQueue(&descriptor);
+        ASSERT_TRUE(ret.isOk());
+
+        resultQueue = std::make_shared<ResultMetadataQueue>(descriptor);
+        if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
+            ALOGE("%s: HAL returns empty result metadata fmq,"
+                  " not use it",
+                  __func__);
+            resultQueue = nullptr;
+            // Don't use the queue onwards.
+        }
+
+        std::shared_ptr<InFlightRequest> inflightReq = std::make_shared<InFlightRequest>(
+                1, false, supportsPartialResults, partialResultCount, resultQueue);
+
+        CameraMetadata req;
+        ret = session->constructDefaultRequestSettings(reqTemplate, &req);
+        ASSERT_TRUE(ret.isOk());
+        settings = req;
+
+        overrideRotateAndCrop(&settings);
+
+        std::vector<CaptureRequest> requests(1);
+        CaptureRequest& request = requests[0];
+        request.frameNumber = frameNumber;
+        request.fmqSettingsSize = 0;
+        request.settings = settings;
+
+        std::vector<StreamBuffer>& outputBuffers = request.outputBuffers;
+        outputBuffers.resize(1);
+        StreamBuffer& outputBuffer = outputBuffers[0];
+        if (useHalBufManager) {
+            outputBuffer = {halStreams[0].id,
+                            /*bufferId*/ 0,   NativeHandle(), BufferStatus::OK,
+                            NativeHandle(),   NativeHandle()};
+        } else {
+            buffer_handle_t handle;
+            allocateGraphicBuffer(
+                    testStream.width, testStream.height,
+                    /* We don't look at halStreamConfig.streams[0].consumerUsage
+                     * since that is 0 for output streams
+                     */
+                    android_convertGralloc1To0Usage(
+                            static_cast<uint64_t>(halStreams[0].producerUsage), bufferUsage),
+                    halStreams[0].overrideFormat, &handle);
+
+            outputBuffer = {halStreams[0].id, bufferId,       ::android::makeToAidl(handle),
+                            BufferStatus::OK, NativeHandle(), NativeHandle()};
+        }
+        request.inputBuffer = {-1,
+                               0,
+                               NativeHandle(),
+                               BufferStatus::ERROR,
+                               NativeHandle(),
+                               NativeHandle()};  // Empty Input Buffer
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            mInflightMap.clear();
+            mInflightMap.insert(std::make_pair(frameNumber, inflightReq));
+        }
+
+        int32_t numRequestProcessed = 0;
+        std::vector<BufferCache> cachesToRemove;
+        ret = session->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+        ALOGI("processCaptureRequestInternal: processCaptureRequest returns status: %d:%d",
+              ret.getExceptionCode(), ret.getServiceSpecificError());
+
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(numRequestProcessed, 1u);
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReq->errorCodeValid &&
+                   ((0 < inflightReq->numBuffersLeft) || (!inflightReq->haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                               std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+            }
+
+            ASSERT_FALSE(inflightReq->errorCodeValid);
+            ASSERT_NE(inflightReq->resultOutputBuffers.size(), 0u);
+            ASSERT_EQ(testStream.id, inflightReq->resultOutputBuffers[0].buffer.streamId);
+
+            // shutterReadoutTimestamp must be available, and it must
+            // be >= shutterTimestamp + exposureTime,
+            // and < shutterTimestamp + exposureTime + rollingShutterSkew / 2.
+            ASSERT_TRUE(inflightReq->shutterReadoutTimestampValid);
+            ASSERT_FALSE(inflightReq->collectedResult.isEmpty());
+
+            if (inflightReq->collectedResult.exists(ANDROID_SENSOR_EXPOSURE_TIME)) {
+                camera_metadata_entry_t exposureTimeResult =
+                        inflightReq->collectedResult.find(ANDROID_SENSOR_EXPOSURE_TIME);
+                nsecs_t exposureToReadout =
+                        inflightReq->shutterReadoutTimestamp - inflightReq->shutterTimestamp;
+                ASSERT_GE(exposureToReadout, exposureTimeResult.data.i64[0]);
+                if (inflightReq->collectedResult.exists(ANDROID_SENSOR_ROLLING_SHUTTER_SKEW)) {
+                    camera_metadata_entry_t rollingShutterSkew =
+                            inflightReq->collectedResult.find(ANDROID_SENSOR_ROLLING_SHUTTER_SKEW);
+                    ASSERT_LT(exposureToReadout,
+                              exposureTimeResult.data.i64[0] + rollingShutterSkew.data.i64[0] / 2);
+                }
+            }
+
+            request.frameNumber++;
+            // Empty settings should be supported after the first call
+            // for repeating requests.
+            request.settings.metadata.clear();
+            // The buffer has been registered to HAL by bufferId, so per
+            // API contract we should send a null handle for this buffer
+            request.outputBuffers[0].buffer = NativeHandle();
+            mInflightMap.clear();
+            inflightReq = std::make_shared<InFlightRequest>(1, false, supportsPartialResults,
+                                                            partialResultCount, resultQueue);
+            mInflightMap.insert(std::make_pair(request.frameNumber, inflightReq));
+        }
+
+        ret = session->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+        ALOGI("processCaptureRequestInternal: processCaptureRequest returns status: %d:%d",
+              ret.getExceptionCode(), ret.getServiceSpecificError());
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(numRequestProcessed, 1u);
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReq->errorCodeValid &&
+                   ((0 < inflightReq->numBuffersLeft) || (!inflightReq->haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                               std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+            }
+
+            ASSERT_FALSE(inflightReq->errorCodeValid);
+            ASSERT_NE(inflightReq->resultOutputBuffers.size(), 0u);
+            ASSERT_EQ(testStream.id, inflightReq->resultOutputBuffers[0].buffer.streamId);
+        }
+
+        if (useHalBufManager) {
+            verifyBuffersReturned(session, testStream.id, cb);
+        }
+
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+void CameraAidlTest::configureSingleStream(
+        const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
+        const AvailableStream* previewThreshold, uint64_t bufferUsage, RequestTemplate reqTemplate,
+        std::shared_ptr<ICameraDeviceSession>* session, Stream* previewStream,
+        std::vector<HalStream>* halStreams, bool* supportsPartialResults,
+        int32_t* partialResultCount, bool* useHalBufManager, std::shared_ptr<DeviceCb>* cb,
+        uint32_t streamConfigCounter) {
+    ASSERT_NE(nullptr, session);
+    ASSERT_NE(nullptr, previewStream);
+    ASSERT_NE(nullptr, halStreams);
+    ASSERT_NE(nullptr, supportsPartialResults);
+    ASSERT_NE(nullptr, partialResultCount);
+    ASSERT_NE(nullptr, useHalBufManager);
+    ASSERT_NE(nullptr, cb);
+
+    std::vector<AvailableStream> outputPreviewStreams;
+    std::shared_ptr<ICameraDevice> device;
+    ALOGI("configureStreams: Testing camera device %s", name.c_str());
+
+    ndk::ScopedAStatus ret = provider->getCameraDeviceInterface(name, &device);
+    ALOGI("getCameraDeviceInterface returns status:%d:%d", ret.getExceptionCode(),
+          ret.getServiceSpecificError());
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_NE(device, nullptr);
+
+    camera_metadata_t* staticMeta;
+    CameraMetadata chars;
+    ret = device->getCameraCharacteristics(&chars);
+    ASSERT_TRUE(ret.isOk());
+    staticMeta = clone_camera_metadata(
+            reinterpret_cast<const camera_metadata_t*>(chars.metadata.data()));
+    ASSERT_NE(nullptr, staticMeta);
+
+    size_t expectedSize = chars.metadata.size();
+    ALOGE("validate_camera_metadata_structure: %d",
+          validate_camera_metadata_structure(staticMeta, &expectedSize));
+
+    camera_metadata_ro_entry entry;
+    auto status =
+            find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry);
+    if ((0 == status) && (entry.count > 0)) {
+        *partialResultCount = entry.data.i32[0];
+        *supportsPartialResults = (*partialResultCount > 1);
+    }
+
+    *cb = ndk::SharedRefBase::make<DeviceCb>(this, staticMeta);
+
+    device->open(*cb, session);
+    ALOGI("device::open returns status:%d:%d", ret.getExceptionCode(),
+          ret.getServiceSpecificError());
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_NE(*session, nullptr);
+
+    *useHalBufManager = false;
+    status = find_camera_metadata_ro_entry(
+            staticMeta, ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
+    if ((0 == status) && (entry.count == 1)) {
+        *useHalBufManager = (entry.data.u8[0] ==
+                             ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+    }
+
+    outputPreviewStreams.clear();
+    auto rc = getAvailableOutputStreams(staticMeta, outputPreviewStreams, previewThreshold);
+
+    int32_t jpegBufferSize = 0;
+    ASSERT_EQ(Status::OK, getJpegBufferSize(staticMeta, &jpegBufferSize));
+    ASSERT_NE(0u, jpegBufferSize);
+
+    ASSERT_EQ(Status::OK, rc);
+    ASSERT_FALSE(outputPreviewStreams.empty());
+
+    Dataspace dataspace = Dataspace::UNKNOWN;
+    switch (static_cast<PixelFormat>(outputPreviewStreams[0].format)) {
+        case PixelFormat::Y16:
+            dataspace = Dataspace::DEPTH;
+            break;
+        default:
+            dataspace = Dataspace::UNKNOWN;
+    }
+
+    std::vector<Stream> streams(1);
+    streams[0] = {0,
+                  StreamType::OUTPUT,
+                  outputPreviewStreams[0].width,
+                  outputPreviewStreams[0].height,
+                  static_cast<PixelFormat>(outputPreviewStreams[0].format),
+                  static_cast<aidl::android::hardware::graphics::common::BufferUsage>(bufferUsage),
+                  dataspace,
+                  StreamRotation::ROTATION_0,
+                  "",
+                  0,
+                  /*groupId*/ -1,
+                  {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                  RequestAvailableDynamicRangeProfilesMap::
+                          ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+
+    StreamConfiguration config;
+    config.streams = streams;
+    createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config,
+                              jpegBufferSize);
+    if (*session != nullptr) {
+        CameraMetadata sessionParams;
+        ret = (*session)->constructDefaultRequestSettings(reqTemplate, &sessionParams);
+        ASSERT_TRUE(ret.isOk());
+        config.sessionParams = sessionParams;
+        config.streamConfigCounter = (int32_t)streamConfigCounter;
+
+        bool supported = false;
+        ret = device->isStreamCombinationSupported(config, &supported);
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(supported, true);
+
+        std::vector<HalStream> halConfigs;
+        ret = (*session)->configureStreams(config, &halConfigs);
+        ALOGI("configureStreams returns status: %d:%d", ret.getExceptionCode(),
+              ret.getServiceSpecificError());
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(1u, halConfigs.size());
+        halStreams->clear();
+        halStreams->push_back(halConfigs[0]);
+        if (*useHalBufManager) {
+            std::vector<Stream> ss(1);
+            std::vector<HalStream> hs(1);
+            ss[0] = config.streams[0];
+            hs[0] = halConfigs[0];
+            (*cb)->setCurrentStreamConfig(ss, hs);
+        }
+    }
+    *previewStream = config.streams[0];
+    ASSERT_TRUE(ret.isOk());
+}
+
+void CameraAidlTest::overrideRotateAndCrop(CameraMetadata* settings) {
+    if (settings == nullptr) {
+        return;
+    }
+
+    ::android::hardware::camera::common::V1_0::helper::CameraMetadata requestMeta =
+            clone_camera_metadata(reinterpret_cast<camera_metadata_t*>(settings->metadata.data()));
+    auto entry = requestMeta.find(ANDROID_SCALER_ROTATE_AND_CROP);
+    if ((entry.count > 0) && (entry.data.u8[0] == ANDROID_SCALER_ROTATE_AND_CROP_AUTO)) {
+        uint8_t disableRotateAndCrop = ANDROID_SCALER_ROTATE_AND_CROP_NONE;
+        requestMeta.update(ANDROID_SCALER_ROTATE_AND_CROP, &disableRotateAndCrop, 1);
+        settings->metadata.clear();
+        camera_metadata_t* metaBuffer = requestMeta.release();
+        uint8_t* rawMetaBuffer = reinterpret_cast<uint8_t*>(metaBuffer);
+        settings->metadata =
+                std::vector(rawMetaBuffer, rawMetaBuffer + get_camera_metadata_size(metaBuffer));
+    }
+}
+
+void CameraAidlTest::verifyBuffersReturned(const std::shared_ptr<ICameraDeviceSession>& session,
+                                           int32_t streamId, const std::shared_ptr<DeviceCb>& cb,
+                                           uint32_t streamConfigCounter) {
+    ASSERT_NE(nullptr, session);
+
+    std::vector<int32_t> streamIds(1);
+    streamIds[0] = streamId;
+    session->signalStreamFlush(streamIds, /*streamConfigCounter*/ streamConfigCounter);
+    cb->waitForBuffersReturned();
+}
+
+void CameraAidlTest::processPreviewStabilizationCaptureRequestInternal(
+        bool previewStabilizationOn,
+        // Used as output when preview stabilization is off, as output when its on.
+        std::unordered_map<std::string, nsecs_t>& cameraDeviceToTimeLag) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    AvailableStream streamThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                       static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+    int64_t bufferId = 1;
+    int32_t frameNumber = 1;
+    std::vector<uint8_t> settings;
+
+    for (const auto& name : cameraDeviceNames) {
+        if (!supportsPreviewStabilization(name, mProvider)) {
+            ALOGI(" %s Camera device %s doesn't support preview stabilization, skipping", __func__,
+                  name.c_str());
+            continue;
+        }
+
+        Stream testStream;
+        std::vector<HalStream> halStreams;
+        std::shared_ptr<ICameraDeviceSession> session;
+        std::shared_ptr<DeviceCb> cb;
+        bool supportsPartialResults = false;
+        bool useHalBufManager = false;
+        int32_t partialResultCount = 0;
+        configureSingleStream(name, mProvider, &streamThreshold, GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                              RequestTemplate::PREVIEW, &session /*out*/, &testStream /*out*/,
+                              &halStreams /*out*/, &supportsPartialResults /*out*/,
+                              &partialResultCount /*out*/, &useHalBufManager /*out*/, &cb /*out*/);
+
+        ::aidl::android::hardware::common::fmq::MQDescriptor<
+                int8_t, aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+                descriptor;
+        ndk::ScopedAStatus resultQueueRet = session->getCaptureResultMetadataQueue(&descriptor);
+        ASSERT_TRUE(resultQueueRet.isOk());
+
+        std::shared_ptr<ResultMetadataQueue> resultQueue =
+                std::make_shared<ResultMetadataQueue>(descriptor);
+        if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
+            ALOGE("%s: HAL returns empty result metadata fmq,"
+                  " not use it",
+                  __func__);
+            resultQueue = nullptr;
+            // Don't use the queue onwards.
+        }
+
+        std::shared_ptr<InFlightRequest> inflightReq = std::make_shared<InFlightRequest>(
+                1, false, supportsPartialResults, partialResultCount, resultQueue);
+
+        CameraMetadata defaultMetadata;
+        android::hardware::camera::common::V1_0::helper::CameraMetadata defaultSettings;
+        ndk::ScopedAStatus ret = session->constructDefaultRequestSettings(RequestTemplate::PREVIEW,
+                                                                          &defaultMetadata);
+        ASSERT_TRUE(ret.isOk());
+
+        const camera_metadata_t* metadata =
+                reinterpret_cast<const camera_metadata_t*>(defaultMetadata.metadata.data());
+        defaultSettings = metadata;
+        android::status_t metadataRet = ::android::OK;
+        uint8_t videoStabilizationMode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
+        if (previewStabilizationOn) {
+            videoStabilizationMode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION;
+            metadataRet = defaultSettings.update(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+                                                 &videoStabilizationMode, 1);
+        } else {
+            metadataRet = defaultSettings.update(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+                                                 &videoStabilizationMode, 1);
+        }
+        ASSERT_EQ(metadataRet, ::android::OK);
+
+        camera_metadata_t* releasedMetadata = defaultSettings.release();
+        uint8_t* rawMetadata = reinterpret_cast<uint8_t*>(releasedMetadata);
+
+        buffer_handle_t buffer_handle;
+
+        std::vector<CaptureRequest> requests(1);
+        CaptureRequest& request = requests[0];
+        request.frameNumber = frameNumber;
+        request.fmqSettingsSize = 0;
+        request.settings.metadata =
+                std::vector(rawMetadata, rawMetadata + get_camera_metadata_size(releasedMetadata));
+        request.outputBuffers = std::vector<StreamBuffer>(1);
+        StreamBuffer& outputBuffer = request.outputBuffers[0];
+        if (useHalBufManager) {
+            outputBuffer = {halStreams[0].id,
+                            /*bufferId*/ 0,   NativeHandle(), BufferStatus::OK,
+                            NativeHandle(),   NativeHandle()};
+        } else {
+            allocateGraphicBuffer(testStream.width, testStream.height,
+                                  /* We don't look at halStreamConfig.streams[0].consumerUsage
+                                   * since that is 0 for output streams
+                                   */
+                                  android_convertGralloc1To0Usage(
+                                          static_cast<uint64_t>(halStreams[0].producerUsage),
+                                          GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
+                                  halStreams[0].overrideFormat, &buffer_handle);
+            outputBuffer = {halStreams[0].id, bufferId,       ::android::makeToAidl(buffer_handle),
+                            BufferStatus::OK, NativeHandle(), NativeHandle()};
+        }
+        request.inputBuffer = {
+                -1, 0, NativeHandle(), BufferStatus::ERROR, NativeHandle(), NativeHandle()};
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            mInflightMap.clear();
+            mInflightMap.insert(std::make_pair(frameNumber, inflightReq));
+        }
+
+        int32_t numRequestProcessed = 0;
+        std::vector<BufferCache> cachesToRemove;
+        ret = session->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(numRequestProcessed, 1u);
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReq->errorCodeValid &&
+                   ((0 < inflightReq->numBuffersLeft) || (!inflightReq->haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                               std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+            }
+
+            ASSERT_FALSE(inflightReq->errorCodeValid);
+            ASSERT_NE(inflightReq->resultOutputBuffers.size(), 0u);
+            ASSERT_EQ(testStream.id, inflightReq->resultOutputBuffers[0].buffer.streamId);
+            ASSERT_TRUE(inflightReq->shutterReadoutTimestampValid);
+            nsecs_t readoutTimestamp = inflightReq->shutterReadoutTimestamp;
+
+            if (previewStabilizationOn) {
+                // Here we collect the time difference between the buffer ready
+                // timestamp - notify readout timestamp.
+                // timeLag = buffer ready timestamp - notify readout timestamp.
+                // timeLag(previewStabilization) must be <=
+                //        timeLag(stabilization off) + 1 frame duration.
+                auto it = cameraDeviceToTimeLag.find(name);
+                camera_metadata_entry e;
+                e = inflightReq->collectedResult.find(ANDROID_SENSOR_FRAME_DURATION);
+                ASSERT_TRUE(e.count > 0);
+                nsecs_t frameDuration = e.data.i64[0];
+                ASSERT_TRUE(it != cameraDeviceToTimeLag.end());
+
+                nsecs_t previewStabOnLagTime =
+                        inflightReq->resultOutputBuffers[0].timeStamp - readoutTimestamp;
+                ASSERT_TRUE(previewStabOnLagTime <= (it->second + frameDuration));
+            } else {
+                // Fill in the buffer ready timestamp - notify timestamp;
+                cameraDeviceToTimeLag[std::string(name)] =
+                        inflightReq->resultOutputBuffers[0].timeStamp - readoutTimestamp;
+            }
+        }
+
+        if (useHalBufManager) {
+            verifyBuffersReturned(session, testStream.id, cb);
+        }
+
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+bool CameraAidlTest::supportsPreviewStabilization(
+        const std::string& name, const std::shared_ptr<ICameraProvider>& provider) {
+    std::shared_ptr<ICameraDevice> device;
+    ndk::ScopedAStatus ret = provider->getCameraDeviceInterface(name, &device);
+    ALOGI("getCameraDeviceInterface returns status:%d:%d", ret.getExceptionCode(),
+          ret.getServiceSpecificError());
+    if (!ret.isOk() || device == nullptr) {
+        ADD_FAILURE() << "Failed to get camera device interface for " << name;
+    }
+
+    CameraMetadata metadata;
+    ret = device->getCameraCharacteristics(&metadata);
+    camera_metadata_t* staticMeta = clone_camera_metadata(
+            reinterpret_cast<const camera_metadata_t*>(metadata.metadata.data()));
+    if (!(ret.isOk())) {
+        ADD_FAILURE() << "Failed to get camera characteristics for " << name;
+    }
+    // Go through the characteristics and see if video stabilization modes have
+    // preview stabilization
+    camera_metadata_ro_entry entry;
+
+    int retcode = find_camera_metadata_ro_entry(
+            staticMeta, ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, &entry);
+    if ((0 == retcode) && (entry.count > 0)) {
+        for (auto i = 0; i < entry.count; i++) {
+            if (entry.data.u8[i] ==
+                ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+void CameraAidlTest::configurePreviewStreams(
+        const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
+        const AvailableStream* previewThreshold, const std::unordered_set<std::string>& physicalIds,
+        std::shared_ptr<ICameraDeviceSession>* session, Stream* previewStream,
+        std::vector<HalStream>* halStreams, bool* supportsPartialResults,
+        int32_t* partialResultCount, bool* useHalBufManager, std::shared_ptr<DeviceCb>* cb,
+        int32_t streamConfigCounter, bool allowUnsupport) {
+    ASSERT_NE(nullptr, session);
+    ASSERT_NE(nullptr, halStreams);
+    ASSERT_NE(nullptr, previewStream);
+    ASSERT_NE(nullptr, supportsPartialResults);
+    ASSERT_NE(nullptr, partialResultCount);
+    ASSERT_NE(nullptr, useHalBufManager);
+    ASSERT_NE(nullptr, cb);
+
+    ASSERT_FALSE(physicalIds.empty());
+
+    std::vector<AvailableStream> outputPreviewStreams;
+    std::shared_ptr<ICameraDevice> device;
+    ALOGI("configureStreams: Testing camera device %s", name.c_str());
+
+    ndk::ScopedAStatus ret = provider->getCameraDeviceInterface(name, &device);
+    ALOGI("getCameraDeviceInterface returns status:%d:%d", ret.getExceptionCode(),
+          ret.getServiceSpecificError());
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_NE(device, nullptr);
+
+    CameraMetadata meta;
+    ret = device->getCameraCharacteristics(&meta);
+    ASSERT_TRUE(ret.isOk());
+    camera_metadata_t* staticMeta =
+            clone_camera_metadata(reinterpret_cast<const camera_metadata_t*>(meta.metadata.data()));
+    ASSERT_NE(nullptr, staticMeta);
+
+    camera_metadata_ro_entry entry;
+    auto status =
+            find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry);
+    if ((0 == status) && (entry.count > 0)) {
+        *partialResultCount = entry.data.i32[0];
+        *supportsPartialResults = (*partialResultCount > 1);
+    }
+
+    *cb = ndk::SharedRefBase::make<DeviceCb>(this, staticMeta);
+    ret = device->open(*cb, session);
+    ALOGI("device::open returns status:%d:%d", ret.getExceptionCode(),
+          ret.getServiceSpecificError());
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_NE(*session, nullptr);
+
+    *useHalBufManager = false;
+    status = find_camera_metadata_ro_entry(
+            staticMeta, ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
+    if ((0 == status) && (entry.count == 1)) {
+        *useHalBufManager = (entry.data.u8[0] ==
+                             ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+    }
+
+    outputPreviewStreams.clear();
+    Status rc = getAvailableOutputStreams(staticMeta, outputPreviewStreams, previewThreshold);
+
+    ASSERT_EQ(Status::OK, rc);
+    ASSERT_FALSE(outputPreviewStreams.empty());
+
+    std::vector<Stream> streams(physicalIds.size());
+    int32_t streamId = 0;
+    for (auto const& physicalId : physicalIds) {
+        streams[streamId] = {streamId,
+                             StreamType::OUTPUT,
+                             outputPreviewStreams[0].width,
+                             outputPreviewStreams[0].height,
+                             static_cast<PixelFormat>(outputPreviewStreams[0].format),
+                             static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
+                                     GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
+                             Dataspace::UNKNOWN,
+                             StreamRotation::ROTATION_0,
+                             physicalId,
+                             0,
+                             -1,
+                             {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                             RequestAvailableDynamicRangeProfilesMap::
+                                     ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+        streamId++;
+    }
+
+    StreamConfiguration config = {streams, StreamConfigurationMode::NORMAL_MODE, CameraMetadata()};
+
+    RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+    ret = (*session)->constructDefaultRequestSettings(reqTemplate, &config.sessionParams);
+    ASSERT_TRUE(ret.isOk());
+
+    bool supported = false;
+    ret = device->isStreamCombinationSupported(config, &supported);
+    ASSERT_TRUE(ret.isOk());
+    if (allowUnsupport && !supported) {
+        // stream combination not supported. return null session
+        ret = (*session)->close();
+        ASSERT_TRUE(ret.isOk());
+        *session = nullptr;
+        return;
+    }
+    ASSERT_TRUE(supported) << "Stream combination must be supported.";
+
+    config.streamConfigCounter = streamConfigCounter;
+    std::vector<HalStream> halConfigs;
+    ret = (*session)->configureStreams(config, &halConfigs);
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_EQ(physicalIds.size(), halConfigs.size());
+    *halStreams = halConfigs;
+    if (*useHalBufManager) {
+        std::vector<Stream> ss(physicalIds.size());
+        std::vector<HalStream> hs(physicalIds.size());
+        for (size_t i = 0; i < physicalIds.size(); i++) {
+            ss[i] = streams[i];
+            hs[i] = halConfigs[i];
+        }
+        (*cb)->setCurrentStreamConfig(ss, hs);
+    }
+    *previewStream = streams[0];
+    ASSERT_TRUE(ret.isOk());
+}
+
+void CameraAidlTest::verifyBuffersReturned(const std::shared_ptr<ICameraDeviceSession>& session,
+                                           const std::vector<int32_t>& streamIds,
+                                           const std::shared_ptr<DeviceCb>& cb,
+                                           uint32_t streamConfigCounter) {
+    ndk::ScopedAStatus ret =
+            session->signalStreamFlush(streamIds, /*streamConfigCounter*/ streamConfigCounter);
+    ASSERT_TRUE(ret.isOk());
+    cb->waitForBuffersReturned();
+}
+
+void CameraAidlTest::configureStreams(const std::string& name,
+                                      const std::shared_ptr<ICameraProvider>& provider,
+                                      PixelFormat format,
+                                      std::shared_ptr<ICameraDeviceSession>* session,
+                                      Stream* previewStream, std::vector<HalStream>* halStreams,
+                                      bool* supportsPartialResults, int32_t* partialResultCount,
+                                      bool* useHalBufManager, std::shared_ptr<DeviceCb>* outCb,
+                                      uint32_t streamConfigCounter, bool maxResolution,
+                                      RequestAvailableDynamicRangeProfilesMap prof) {
+    ASSERT_NE(nullptr, session);
+    ASSERT_NE(nullptr, halStreams);
+    ASSERT_NE(nullptr, previewStream);
+    ASSERT_NE(nullptr, supportsPartialResults);
+    ASSERT_NE(nullptr, partialResultCount);
+    ASSERT_NE(nullptr, useHalBufManager);
+    ASSERT_NE(nullptr, outCb);
+
+    ALOGI("configureStreams: Testing camera device %s", name.c_str());
+
+    std::vector<AvailableStream> outputStreams;
+    std::shared_ptr<ICameraDevice> device;
+
+    ndk::ScopedAStatus ret = provider->getCameraDeviceInterface(name, &device);
+    ALOGI("getCameraDeviceInterface returns status:%d:%d", ret.getExceptionCode(),
+          ret.getServiceSpecificError());
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_NE(device, nullptr);
+
+    CameraMetadata metadata;
+    camera_metadata_t* staticMeta;
+    ret = device->getCameraCharacteristics(&metadata);
+    ASSERT_TRUE(ret.isOk());
+    staticMeta = clone_camera_metadata(
+            reinterpret_cast<const camera_metadata_t*>(metadata.metadata.data()));
+    ASSERT_NE(staticMeta, nullptr);
+
+    camera_metadata_ro_entry entry;
+    auto status =
+            find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry);
+    if ((0 == status) && (entry.count > 0)) {
+        *partialResultCount = entry.data.i32[0];
+        *supportsPartialResults = (*partialResultCount > 1);
+    }
+
+    *outCb = ndk::SharedRefBase::make<DeviceCb>(this, staticMeta);
+    ret = device->open(*outCb, session);
+    ALOGI("device::open returns status:%d:%d", ret.getExceptionCode(),
+          ret.getServiceSpecificError());
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_NE(*session, nullptr);
+
+    *useHalBufManager = false;
+    status = find_camera_metadata_ro_entry(
+            staticMeta, ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
+    if ((0 == status) && (entry.count == 1)) {
+        *useHalBufManager = (entry.data.u8[0] ==
+                             ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+    }
+
+    outputStreams.clear();
+    Size maxSize;
+    auto rc = getMaxOutputSizeForFormat(staticMeta, format, &maxSize, maxResolution);
+    ASSERT_EQ(Status::OK, rc);
+
+    std::vector<Stream> streams(1);
+    streams[0] = {0,
+                  StreamType::OUTPUT,
+                  maxSize.width,
+                  maxSize.height,
+                  format,
+                  static_cast<::aidl::android::hardware::graphics::common::BufferUsage>(
+                          GRALLOC1_CONSUMER_USAGE_CPU_READ),
+                  Dataspace::UNKNOWN,
+                  StreamRotation::ROTATION_0,
+                  "",
+                  0,
+                  -1,
+                  {maxResolution ? SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION
+                                 : SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                  prof};
+
+    StreamConfiguration config;
+    config.streams = streams;
+    config.operationMode = StreamConfigurationMode::NORMAL_MODE;
+    config.streamConfigCounter = streamConfigCounter;
+    config.multiResolutionInputImage = false;
+    CameraMetadata req;
+    RequestTemplate reqTemplate = RequestTemplate::STILL_CAPTURE;
+    ret = (*session)->constructDefaultRequestSettings(reqTemplate, &req);
+    ASSERT_TRUE(ret.isOk());
+    config.sessionParams = req;
+
+    bool supported = false;
+    ret = device->isStreamCombinationSupported(config, &supported);
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_EQ(supported, true);
+
+    ret = (*session)->configureStreams(config, halStreams);
+    ASSERT_TRUE(ret.isOk());
+
+    if (*useHalBufManager) {
+        std::vector<Stream> ss(1);
+        std::vector<HalStream> hs(1);
+        ss[0] = streams[0];
+        hs[0] = (*halStreams)[0];
+        (*outCb)->setCurrentStreamConfig(ss, hs);
+    }
+
+    *previewStream = streams[0];
+    ASSERT_TRUE(ret.isOk());
+}
+
+bool CameraAidlTest::is10BitDynamicRangeCapable(const camera_metadata_t* staticMeta) {
+    camera_metadata_ro_entry scalerEntry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                           &scalerEntry);
+    if (rc == 0) {
+        for (uint32_t i = 0; i < scalerEntry.count; i++) {
+            if (scalerEntry.data.u8[i] ==
+                ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+void CameraAidlTest::get10BitDynamicRangeProfiles(
+        const camera_metadata_t* staticMeta,
+        std::vector<RequestAvailableDynamicRangeProfilesMap>* profiles) {
+    ASSERT_NE(nullptr, staticMeta);
+    ASSERT_NE(nullptr, profiles);
+    camera_metadata_ro_entry entry;
+    std::unordered_set<int64_t> entries;
+    int rc = find_camera_metadata_ro_entry(
+            staticMeta, ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP, &entry);
+    ASSERT_EQ(rc, 0);
+    ASSERT_TRUE(entry.count > 0);
+    ASSERT_EQ(entry.count % 3, 0);
+
+    for (uint32_t i = 0; i < entry.count; i += 3) {
+        ASSERT_NE(entry.data.i64[i], ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
+        ASSERT_EQ(entries.find(entry.data.i64[i]), entries.end());
+        entries.insert(static_cast<int64_t>(entry.data.i64[i]));
+        profiles->emplace_back(
+                static_cast<RequestAvailableDynamicRangeProfilesMap>(entry.data.i64[i]));
+    }
+
+    if (!entries.empty()) {
+        ASSERT_NE(entries.find(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10),
+                  entries.end());
+    }
+}
+
+void CameraAidlTest::verify10BitMetadata(
+        HandleImporter& importer, const InFlightRequest& request,
+        aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap
+                profile) {
+    for (const auto& b : request.resultOutputBuffers) {
+        bool smpte2086Present = importer.isSmpte2086Present(b.buffer.buffer);
+        bool smpte2094_10Present = importer.isSmpte2094_10Present(b.buffer.buffer);
+        bool smpte2094_40Present = importer.isSmpte2094_40Present(b.buffer.buffer);
+
+        switch (static_cast<int64_t>(profile)) {
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10:
+                ASSERT_FALSE(smpte2086Present);
+                ASSERT_FALSE(smpte2094_10Present);
+                ASSERT_FALSE(smpte2094_40Present);
+                break;
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10:
+                ASSERT_TRUE(smpte2086Present);
+                ASSERT_FALSE(smpte2094_10Present);
+                ASSERT_FALSE(smpte2094_40Present);
+                break;
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS:
+                ASSERT_FALSE(smpte2086Present);
+                ASSERT_FALSE(smpte2094_10Present);
+                ASSERT_TRUE(smpte2094_40Present);
+                break;
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF:
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO:
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM:
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO:
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF:
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO:
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM:
+            case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO:
+                ASSERT_FALSE(smpte2086Present);
+                ASSERT_TRUE(smpte2094_10Present);
+                ASSERT_FALSE(smpte2094_40Present);
+                break;
+            default:
+                ALOGE("%s: Unexpected 10-bit dynamic range profile: %" PRId64, __FUNCTION__,
+                      profile);
+                ADD_FAILURE();
+        }
+    }
+}
+
+void CameraAidlTest::configurePreviewStream(
+        const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
+        const AvailableStream* previewThreshold, std::shared_ptr<ICameraDeviceSession>* session,
+        Stream* previewStream, std::vector<HalStream>* halStreams, bool* supportsPartialResults,
+        int32_t* partialResultCount, bool* useHalBufManager, std::shared_ptr<DeviceCb>* cb,
+        uint32_t streamConfigCounter) {
+    configureSingleStream(name, provider, previewThreshold, GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                          RequestTemplate::PREVIEW, session, previewStream, halStreams,
+                          supportsPartialResults, partialResultCount, useHalBufManager, cb,
+                          streamConfigCounter);
+}
+
+Status CameraAidlTest::isOfflineSessionSupported(const camera_metadata_t* staticMeta) {
+    Status ret = Status::OPERATION_NOT_SUPPORTED;
+    if (nullptr == staticMeta) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                           &entry);
+    if (0 != rc) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    for (size_t i = 0; i < entry.count; i++) {
+        if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING == entry.data.u8[i]) {
+            ret = Status::OK;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+void CameraAidlTest::configureOfflineStillStream(
+        const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
+        const AvailableStream* threshold, std::shared_ptr<ICameraDeviceSession>* session,
+        Stream* stream, std::vector<HalStream>* halStreams, bool* supportsPartialResults,
+        int32_t* partialResultCount, std::shared_ptr<DeviceCb>* outCb, int32_t* jpegBufferSize,
+        bool* useHalBufManager) {
+    ASSERT_NE(nullptr, session);
+    ASSERT_NE(nullptr, halStreams);
+    ASSERT_NE(nullptr, stream);
+    ASSERT_NE(nullptr, supportsPartialResults);
+    ASSERT_NE(nullptr, partialResultCount);
+    ASSERT_NE(nullptr, outCb);
+    ASSERT_NE(nullptr, jpegBufferSize);
+    ASSERT_NE(nullptr, useHalBufManager);
+
+    std::vector<AvailableStream> outputStreams;
+    std::shared_ptr<ICameraDevice> cameraDevice;
+    ALOGI("configureStreams: Testing camera device %s", name.c_str());
+
+    ndk::ScopedAStatus ret = provider->getCameraDeviceInterface(name, &cameraDevice);
+    ASSERT_TRUE(ret.isOk());
+    ALOGI("getCameraDeviceInterface returns status:%d:%d", ret.getExceptionCode(),
+          ret.getServiceSpecificError());
+    ASSERT_NE(cameraDevice, nullptr);
+
+    CameraMetadata metadata;
+    ret = cameraDevice->getCameraCharacteristics(&metadata);
+    ASSERT_TRUE(ret.isOk());
+    camera_metadata_t* staticMeta = clone_camera_metadata(
+            reinterpret_cast<const camera_metadata_t*>(metadata.metadata.data()));
+    ASSERT_NE(nullptr, staticMeta);
+
+    camera_metadata_ro_entry entry;
+    auto status =
+            find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry);
+    if ((0 == status) && (entry.count > 0)) {
+        *partialResultCount = entry.data.i32[0];
+        *supportsPartialResults = (*partialResultCount > 1);
+    }
+
+    *useHalBufManager = false;
+    status = find_camera_metadata_ro_entry(
+            staticMeta, ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
+    if ((0 == status) && (entry.count == 1)) {
+        *useHalBufManager = (entry.data.u8[0] ==
+                             ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+    }
+
+    auto st = getJpegBufferSize(staticMeta, jpegBufferSize);
+    ASSERT_EQ(st, Status::OK);
+
+    *outCb = ndk::SharedRefBase::make<DeviceCb>(this, staticMeta);
+    ret = cameraDevice->open(*outCb, session);
+    ASSERT_TRUE(ret.isOk());
+    ALOGI("device::open returns status:%d:%d", ret.getExceptionCode(),
+          ret.getServiceSpecificError());
+    ASSERT_NE(session, nullptr);
+
+    outputStreams.clear();
+    auto rc = getAvailableOutputStreams(staticMeta, outputStreams, threshold);
+    size_t idx = 0;
+    int currLargest = outputStreams[0].width * outputStreams[0].height;
+    for (size_t i = 0; i < outputStreams.size(); i++) {
+        int area = outputStreams[i].width * outputStreams[i].height;
+        if (area > currLargest) {
+            idx = i;
+            currLargest = area;
+        }
+    }
+
+    ASSERT_EQ(Status::OK, rc);
+    ASSERT_FALSE(outputStreams.empty());
+
+    Dataspace dataspace = getDataspace(static_cast<PixelFormat>(outputStreams[idx].format));
+
+    std::vector<Stream> streams(/*size*/ 1);
+    streams[0] = {/*id*/ 0,
+                  StreamType::OUTPUT,
+                  outputStreams[idx].width,
+                  outputStreams[idx].height,
+                  static_cast<PixelFormat>(outputStreams[idx].format),
+                  static_cast<::aidl::android::hardware::graphics::common::BufferUsage>(
+                          GRALLOC1_CONSUMER_USAGE_CPU_READ),
+                  dataspace,
+                  StreamRotation::ROTATION_0,
+                  /*physicalId*/ std::string(),
+                  *jpegBufferSize,
+                  /*groupId*/ 0,
+                  {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                  RequestAvailableDynamicRangeProfilesMap::
+                          ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+
+    StreamConfiguration config = {streams, StreamConfigurationMode::NORMAL_MODE, CameraMetadata()};
+
+    (*session)->configureStreams(config, halStreams);
+    ASSERT_TRUE(ret.isOk());
+
+    if (*useHalBufManager) {
+        (*outCb)->setCurrentStreamConfig(streams, *halStreams);
+    }
+
+    *stream = streams[0];
+}
+
+void CameraAidlTest::updateInflightResultQueue(
+        const std::shared_ptr<ResultMetadataQueue>& resultQueue) {
+    std::unique_lock<std::mutex> l(mLock);
+    for (auto& it : mInflightMap) {
+        it.second->resultQueue = resultQueue;
+    }
+}
\ No newline at end of file
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
new file mode 100644
index 0000000..ac4b2c9
--- /dev/null
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_CAMERA_AIDL_TEST_H_
+#define HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_CAMERA_AIDL_TEST_H_
+
+#define LOG_TAG "camera_aidl_hal_test"
+
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <CameraMetadata.h>
+#include <CameraParameters.h>
+#include <HandleImporter.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include <aidl/android/hardware/graphics/common/Dataspace.h>
+
+#include <aidl/android/hardware/camera/common/Status.h>
+#include <aidl/android/hardware/camera/common/TorchModeStatus.h>
+#include <aidl/android/hardware/common/NativeHandle.h>
+
+#include <aidl/android/hardware/camera/device/CaptureResult.h>
+#include <aidl/android/hardware/camera/device/ErrorCode.h>
+#include <aidl/android/hardware/camera/device/HalStream.h>
+#include <aidl/android/hardware/camera/device/ICameraDevice.h>
+#include <aidl/android/hardware/camera/device/NotifyMsg.h>
+#include <aidl/android/hardware/camera/device/PhysicalCameraMetadata.h>
+#include <aidl/android/hardware/camera/device/Stream.h>
+
+#include <aidl/android/hardware/camera/provider/ICameraProvider.h>
+
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+
+#include <gtest/gtest.h>
+
+#include <log/log.h>
+#include <system/camera_metadata.h>
+#include <utils/KeyedVector.h>
+#include <utils/Timers.h>
+
+using ::aidl::android::hardware::camera::common::Status;
+using ::aidl::android::hardware::camera::common::TorchModeStatus;
+using ::aidl::android::hardware::camera::device::BufferRequest;
+using ::aidl::android::hardware::camera::device::BufferRequestStatus;
+using ::aidl::android::hardware::camera::device::CameraMetadata;
+using ::aidl::android::hardware::camera::device::CaptureResult;
+using ::aidl::android::hardware::camera::device::ErrorCode;
+using ::aidl::android::hardware::camera::device::HalStream;
+using ::aidl::android::hardware::camera::device::ICameraDevice;
+using ::aidl::android::hardware::camera::device::ICameraDeviceSession;
+using ::aidl::android::hardware::camera::device::ICameraInjectionSession;
+using ::aidl::android::hardware::camera::device::NotifyMsg;
+using ::aidl::android::hardware::camera::device::PhysicalCameraMetadata;
+using ::aidl::android::hardware::camera::device::RequestTemplate;
+using ::aidl::android::hardware::camera::device::Stream;
+using ::aidl::android::hardware::camera::device::StreamBuffer;
+using ::aidl::android::hardware::camera::device::StreamBufferRet;
+using ::aidl::android::hardware::camera::device::StreamConfiguration;
+using ::aidl::android::hardware::camera::device::StreamConfigurationMode;
+using ::aidl::android::hardware::camera::provider::ConcurrentCameraIdCombination;
+using ::aidl::android::hardware::camera::provider::ICameraProvider;
+
+using ::aidl::android::hardware::common::NativeHandle;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+
+using ::aidl::android::hardware::graphics::common::Dataspace;
+using ::aidl::android::hardware::graphics::common::PixelFormat;
+
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::common::V1_0::helper::Size;
+
+using ResultMetadataQueue = android::AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+
+using ::ndk::ScopedAStatus;
+
+class DeviceCb;  // Forward declare to break circular header dependency
+
+class CameraAidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    enum SystemCameraKind {
+        /**
+         * These camera devices are visible to all apps and system components alike
+         */
+        PUBLIC = 0,
+
+        /**
+         * These camera devices are visible only to processes having the
+         * android.permission.SYSTEM_CAMERA permission. They are not exposed to 3P
+         * apps.
+         */
+        SYSTEM_ONLY_CAMERA,
+
+        /**
+         * These camera devices are visible only to HAL clients (that try to connect
+         * on a hwbinder thread).
+         */
+        HIDDEN_SECURE_CAMERA
+    };
+
+    struct AvailableStream {
+        int32_t width;
+        int32_t height;
+        int32_t format;
+    };
+
+    enum ReprocessType {
+        PRIV_REPROCESS,
+        YUV_REPROCESS,
+    };
+
+    struct AvailableZSLInputOutput {
+        int32_t inputFormat;
+        int32_t outputFormat;
+    };
+
+    virtual void SetUp() override;
+    virtual void TearDown() override;
+
+    std::vector<std::string> getCameraDeviceNames(std::shared_ptr<ICameraProvider>& provider,
+                                                  bool addSecureOnly = false);
+
+    static bool isSecureOnly(const std::shared_ptr<ICameraProvider>& provider,
+                             const std::string& name);
+
+    std::map<std::string, std::string> getCameraDeviceIdToNameMap(
+            std::shared_ptr<ICameraProvider> provider);
+
+    static std::vector<ConcurrentCameraIdCombination> getConcurrentDeviceCombinations(
+            std::shared_ptr<ICameraProvider>& provider);
+
+    void notifyDeviceState(int64_t state);
+
+    static void allocateGraphicBuffer(uint32_t width, uint32_t height, uint64_t usage,
+                                      PixelFormat format, buffer_handle_t* buffer_handle /*out*/);
+
+    static void openEmptyDeviceSession(const std::string& name,
+                                       const std::shared_ptr<ICameraProvider>& provider,
+                                       std::shared_ptr<ICameraDeviceSession>* session /*out*/,
+                                       CameraMetadata* staticMeta /*out*/,
+                                       std::shared_ptr<ICameraDevice>* device /*out*/);
+    static void openEmptyInjectionSession(const std::string& name,
+                                          const std::shared_ptr<ICameraProvider>& provider,
+                                          std::shared_ptr<ICameraInjectionSession>* session /*out*/,
+                                          CameraMetadata* staticMeta /*out*/,
+                                          std::shared_ptr<ICameraDevice>* device /*out*/);
+
+    static void createStreamConfiguration(std::vector<Stream>& streams,
+                                          StreamConfigurationMode configMode,
+                                          StreamConfiguration* config, int32_t jpegBufferSize = 0);
+
+    void configureOfflineStillStream(
+            const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
+            const AvailableStream* threshold,
+            std::shared_ptr<ICameraDeviceSession>* session /*out*/, Stream* stream /*out*/,
+            std::vector<HalStream>* halStreams, bool* supportsPartialResults /*out*/,
+            int32_t* partialResultCount /*out*/, std::shared_ptr<DeviceCb>* outCb /*out*/,
+            int32_t* jpegBufferSize /*out*/, bool* useHalBufManager /*out*/);
+
+    void configureStreams(
+            const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
+            PixelFormat format, std::shared_ptr<ICameraDeviceSession>* session /*out*/,
+            Stream* previewStream /*out*/, std::vector<HalStream>* halStreams /*out*/,
+            bool* supportsPartialResults /*out*/, int32_t* partialResultCount /*out*/,
+            bool* useHalBufManager /*out*/, std::shared_ptr<DeviceCb>* outCb /*out*/,
+            uint32_t streamConfigCounter, bool maxResolution,
+            aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap
+                    prof = ::aidl::android::hardware::camera::metadata::
+                            RequestAvailableDynamicRangeProfilesMap::
+                                    ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
+
+    void configurePreviewStreams(
+            const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
+            const AvailableStream* previewThreshold,
+            const std::unordered_set<std::string>& physicalIds,
+            std::shared_ptr<ICameraDeviceSession>* session /*out*/, Stream* previewStream /*out*/,
+            std::vector<HalStream>* halStreams /*out*/, bool* supportsPartialResults /*out*/,
+            int32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
+            std::shared_ptr<DeviceCb>* cb /*out*/, int32_t streamConfigCounter = 0,
+            bool allowUnsupport = false);
+
+    void configurePreviewStream(
+            const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
+            const AvailableStream* previewThreshold,
+            std::shared_ptr<ICameraDeviceSession>* session /*out*/, Stream* previewStream /*out*/,
+            std::vector<HalStream>* halStreams /*out*/, bool* supportsPartialResults /*out*/,
+            int32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
+            std::shared_ptr<DeviceCb>* cb /*out*/, uint32_t streamConfigCounter = 0);
+
+    void configureSingleStream(
+            const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
+            const AvailableStream* previewThreshold, uint64_t bufferUsage,
+            RequestTemplate reqTemplate, std::shared_ptr<ICameraDeviceSession>* session /*out*/,
+            Stream* previewStream /*out*/, std::vector<HalStream>* halStreams /*out*/,
+            bool* supportsPartialResults /*out*/, int32_t* partialResultCount /*out*/,
+            bool* useHalBufManager /*out*/, std::shared_ptr<DeviceCb>* cb /*out*/,
+            uint32_t streamConfigCounter = 0);
+
+    void verifyLogicalOrUltraHighResCameraMetadata(const std::string& cameraName,
+                                                   const std::shared_ptr<ICameraDevice>& device,
+                                                   const CameraMetadata& chars,
+                                                   const std::vector<std::string>& deviceNames);
+
+    static void verifyCameraCharacteristics(const CameraMetadata& chars);
+
+    static void verifyExtendedSceneModeCharacteristics(const camera_metadata_t* metadata);
+
+    static void verifyZoomCharacteristics(const camera_metadata_t* metadata);
+
+    static void verifyRecommendedConfigs(const CameraMetadata& chars);
+
+    static void verifyMonochromeCharacteristics(const CameraMetadata& chars);
+
+    static void verifyMonochromeCameraResult(
+            const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& metadata);
+
+    static void verifyStreamUseCaseCharacteristics(const camera_metadata_t* metadata);
+
+    static void verifyStreamCombination(const std::shared_ptr<ICameraDevice>& device,
+                                        const StreamConfiguration& config, bool expectedStatus,
+                                        bool expectStreamCombQuery);
+
+    static void verifyLogicalCameraResult(const camera_metadata_t* staticMetadata,
+                                          const std::vector<uint8_t>& resultMetadata);
+
+    static void verifyBuffersReturned(const std::shared_ptr<ICameraDeviceSession>& session,
+                                      int32_t streamId, const std::shared_ptr<DeviceCb>& cb,
+                                      uint32_t streamConfigCounter = 0);
+
+    void verifyBuffersReturned(const std::shared_ptr<ICameraDeviceSession>& session,
+                               const std::vector<int32_t>& streamIds,
+                               const std::shared_ptr<DeviceCb>& cb,
+                               uint32_t streamConfigCounter = 0);
+
+    static void verifySessionReconfigurationQuery(
+            const std::shared_ptr<ICameraDeviceSession>& session, camera_metadata* oldSessionParams,
+            camera_metadata* newSessionParams);
+
+    static void verifyRequestTemplate(const camera_metadata_t* metadata,
+                                      RequestTemplate requestTemplate);
+
+    static void overrideRotateAndCrop(CameraMetadata* settings /*in/out*/);
+
+    static bool isDepthOnly(const camera_metadata_t* staticMeta);
+
+    static bool isUltraHighResolution(const camera_metadata_t* staticMeta);
+
+    static Status getAvailableOutputStreams(const camera_metadata_t* staticMeta,
+                                            std::vector<AvailableStream>& outputStreams,
+                                            const AvailableStream* threshold = nullptr,
+                                            bool maxResolution = false);
+
+    static Status getMaxOutputSizeForFormat(const camera_metadata_t* staticMeta, PixelFormat format,
+                                            Size* size, bool maxResolution = false);
+
+    static Status getMandatoryConcurrentStreams(const camera_metadata_t* staticMeta,
+                                                std::vector<AvailableStream>* outputStreams);
+
+    static bool supportsPreviewStabilization(const std::string& name,
+                                             const std::shared_ptr<ICameraProvider>& provider);
+
+    static Status getJpegBufferSize(camera_metadata_t* staticMeta, int32_t* outBufSize);
+
+    static Status isConstrainedModeAvailable(camera_metadata_t* staticMeta);
+
+    static Status isLogicalMultiCamera(const camera_metadata_t* staticMeta);
+
+    static bool isTorchSupported(const camera_metadata_t* staticMeta);
+
+    static bool isTorchStrengthControlSupported(const camera_metadata_t* staticMeta);
+
+    static Status isOfflineSessionSupported(const camera_metadata_t* staticMeta);
+
+    static Status getPhysicalCameraIds(const camera_metadata_t* staticMeta,
+                                       std::unordered_set<std::string>* physicalIds /*out*/);
+
+    static Status getSupportedKeys(camera_metadata_t* staticMeta, uint32_t tagId,
+                                   std::unordered_set<int32_t>* requestIDs /*out*/);
+
+    static void fillOutputStreams(camera_metadata_ro_entry_t* entry,
+                                  std::vector<AvailableStream>& outputStreams,
+                                  const AvailableStream* threshold = nullptr,
+                                  const int32_t availableConfigOutputTag = 0u);
+
+    static void constructFilteredSettings(
+            const std::shared_ptr<ICameraDeviceSession>& session,
+            const std::unordered_set<int32_t>& availableKeys, RequestTemplate reqTemplate,
+            android::hardware::camera::common::V1_0::helper::CameraMetadata*
+                    defaultSettings /*out*/,
+            android::hardware::camera::common::V1_0::helper::CameraMetadata* filteredSettings
+            /*out*/);
+
+    static Status pickConstrainedModeSize(camera_metadata_t* staticMeta,
+                                          AvailableStream& hfrStream);
+
+    static Status isZSLModeAvailable(const camera_metadata_t* staticMeta);
+
+    static Status isZSLModeAvailable(const camera_metadata_t* staticMeta, ReprocessType reprocType);
+
+    static Status getZSLInputOutputMap(camera_metadata_t* staticMeta,
+                                       std::vector<AvailableZSLInputOutput>& inputOutputMap);
+
+    static Status findLargestSize(const std::vector<AvailableStream>& streamSizes, int32_t format,
+                                  AvailableStream& result);
+
+    static Status isMonochromeCamera(const camera_metadata_t* staticMeta);
+
+    static Status getSystemCameraKind(const camera_metadata_t* staticMeta,
+                                      SystemCameraKind* systemCameraKind);
+
+    static void getMultiResolutionStreamConfigurations(
+            camera_metadata_ro_entry* multiResStreamConfigs,
+            camera_metadata_ro_entry* streamConfigs,
+            camera_metadata_ro_entry* maxResolutionStreamConfigs,
+            const camera_metadata_t* staticMetadata);
+
+    static void getPrivacyTestPatternModes(
+            const camera_metadata_t* staticMetadata,
+            std::unordered_set<int32_t>* privacyTestPatternModes /*out*/);
+
+    static Dataspace getDataspace(PixelFormat format);
+
+    void processCaptureRequestInternal(uint64_t bufferUsage, RequestTemplate reqTemplate,
+                                       bool useSecureOnlyCameras);
+
+    void processPreviewStabilizationCaptureRequestInternal(
+            bool previewStabilizationOn,
+            /*inout*/ std::unordered_map<std::string, nsecs_t>& cameraDeviceToTimeLag);
+
+    static bool is10BitDynamicRangeCapable(const camera_metadata_t* staticMeta);
+
+    static void get10BitDynamicRangeProfiles(
+            const camera_metadata_t* staticMeta,
+            std::vector<aidl::android::hardware::camera::metadata::
+                                RequestAvailableDynamicRangeProfilesMap>* profiles);
+
+    // Used by switchToOffline where a new result queue is created for offline reqs
+    void updateInflightResultQueue(const std::shared_ptr<ResultMetadataQueue>& resultQueue);
+
+    static Size getMinSize(Size a, Size b);
+
+  protected:
+    // In-flight queue for tracking completion of capture requests.
+    struct InFlightRequest {
+        // Set by notify() SHUTTER call.
+        nsecs_t shutterTimestamp;
+
+        bool shutterReadoutTimestampValid;
+        nsecs_t shutterReadoutTimestamp;
+
+        bool errorCodeValid;
+        ErrorCode errorCode;
+
+        // Is partial result supported
+        bool usePartialResult;
+
+        // Partial result count expected
+        int32_t numPartialResults;
+
+        // Message queue
+        std::shared_ptr<ResultMetadataQueue> resultQueue;
+
+        // Set by process_capture_result call with valid metadata
+        bool haveResultMetadata;
+
+        // Decremented by calls to process_capture_result with valid output
+        // and input buffers
+        ssize_t numBuffersLeft;
+
+        // A 64bit integer to index the frame number associated with this result.
+        int64_t frameNumber;
+
+        // The partial result count (index) for this capture result.
+        int32_t partialResultCount;
+
+        // For buffer drop errors, the stream ID for the stream that lost a buffer.
+        // For physical sub-camera result errors, the Id of the physical stream
+        // for the physical sub-camera.
+        // Otherwise -1.
+        int32_t errorStreamId;
+
+        // If this request has any input buffer
+        bool hasInputBuffer;
+
+        // Result metadata
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata collectedResult;
+
+        // A copy-able StreamBuffer using buffer_handle_t instead of AIDLs NativeHandle
+        struct NativeStreamBuffer {
+            int32_t streamId;
+            int64_t bufferId;
+            buffer_handle_t buffer;
+            aidl::android::hardware::camera::device::BufferStatus status;
+            buffer_handle_t acquireFence;
+            buffer_handle_t releaseFence;
+        };
+
+        // Buffers are added by process_capture_result when output buffers
+        // return from HAL but framework.
+        struct StreamBufferAndTimestamp {
+            NativeStreamBuffer buffer;
+            nsecs_t timeStamp;
+        };
+        std::vector<StreamBufferAndTimestamp> resultOutputBuffers;
+
+        std::unordered_set<std::string> expectedPhysicalResults;
+
+        InFlightRequest()
+            : shutterTimestamp(0),
+              shutterReadoutTimestampValid(false),
+              shutterReadoutTimestamp(0),
+              errorCodeValid(false),
+              errorCode(ErrorCode::ERROR_BUFFER),
+              usePartialResult(false),
+              numPartialResults(0),
+              resultQueue(nullptr),
+              haveResultMetadata(false),
+              numBuffersLeft(0),
+              frameNumber(0),
+              partialResultCount(0),
+              errorStreamId(-1),
+              hasInputBuffer(false),
+              collectedResult(1, 10) {}
+
+        InFlightRequest(ssize_t numBuffers, bool hasInput, bool partialResults,
+                        int32_t partialCount, std::shared_ptr<ResultMetadataQueue> queue = nullptr)
+            : shutterTimestamp(0),
+              shutterReadoutTimestampValid(false),
+              shutterReadoutTimestamp(0),
+              errorCodeValid(false),
+              errorCode(ErrorCode::ERROR_BUFFER),
+              usePartialResult(partialResults),
+              numPartialResults(partialCount),
+              resultQueue(queue),
+              haveResultMetadata(false),
+              numBuffersLeft(numBuffers),
+              frameNumber(0),
+              partialResultCount(0),
+              errorStreamId(-1),
+              hasInputBuffer(hasInput),
+              collectedResult(1, 10) {}
+
+        InFlightRequest(ssize_t numBuffers, bool hasInput, bool partialResults,
+                        int32_t partialCount,
+                        const std::unordered_set<std::string>& extraPhysicalResult,
+                        std::shared_ptr<ResultMetadataQueue> queue = nullptr)
+            : shutterTimestamp(0),
+              shutterReadoutTimestampValid(false),
+              shutterReadoutTimestamp(0),
+              errorCodeValid(false),
+              errorCode(ErrorCode::ERROR_BUFFER),
+              usePartialResult(partialResults),
+              numPartialResults(partialCount),
+              resultQueue(queue),
+              haveResultMetadata(false),
+              numBuffersLeft(numBuffers),
+              frameNumber(0),
+              partialResultCount(0),
+              errorStreamId(-1),
+              hasInputBuffer(hasInput),
+              collectedResult(1, 10),
+              expectedPhysicalResults(extraPhysicalResult) {}
+    };
+
+    static bool matchDeviceName(const std::string& deviceName, const std::string& providerType,
+                                std::string* deviceVersion, std::string* cameraId);
+
+    static void verify10BitMetadata(
+            HandleImporter& importer, const InFlightRequest& request,
+            aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap
+                    profile);
+
+    // Map from frame number to the in-flight request state
+    typedef std::unordered_map<uint32_t, std::shared_ptr<InFlightRequest>> InFlightMap;
+
+    std::mutex mLock;                          // Synchronize access to member variables
+    std::condition_variable mResultCondition;  // Condition variable for incoming results
+    InFlightMap mInflightMap;                  // Map of all inflight requests
+
+    std::vector<NotifyMsg> mNotifyMessages;  // Current notification message
+
+    std::mutex mTorchLock;               // Synchronize access to torch status
+    std::condition_variable mTorchCond;  // Condition variable for torch status
+    TorchModeStatus mTorchStatus;        // Current torch status
+
+    // Camera provider service
+    std::shared_ptr<ICameraProvider> mProvider;
+
+    // Camera device session used by the tests
+    // Tests should take care of closing this session and setting it back to nullptr in successful
+    // case. Declared as a field to allow TeadDown function to close the session if a test assertion
+    // fails.
+    std::shared_ptr<ICameraDeviceSession> mSession;
+
+    // Camera provider type.
+    std::string mProviderType;
+
+    HandleImporter mHandleImporter;
+
+    friend class DeviceCb;
+    friend class SimpleDeviceCb;
+    friend class TorchProviderCb;
+};
+
+namespace {
+// device@<major>.<minor>/<type>/id
+const char* kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/\\s+/(.+)";
+const int32_t kMaxVideoWidth = 4096;
+const int32_t kMaxVideoHeight = 2160;
+
+const int64_t kStreamBufferTimeoutSec = 3;
+const int64_t kTorchTimeoutSec = 1;
+const char* kDumpOutput = "/dev/null";
+const uint32_t kMaxPreviewWidth = 1920;
+const uint32_t kMaxPreviewHeight = 1080;
+}  // namespace
+#endif  // HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_CAMERA_AIDL_TEST_H_
diff --git a/camera/provider/aidl/vts/device_cb.cpp b/camera/provider/aidl/vts/device_cb.cpp
new file mode 100644
index 0000000..e5f2f1e
--- /dev/null
+++ b/camera/provider/aidl/vts/device_cb.cpp
@@ -0,0 +1,544 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "device_cb.h"
+
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <grallocusage/GrallocUsageConversion.h>
+#include <ui/Fence.h>
+#include <cinttypes>
+
+using ::aidl::android::hardware::camera::device::BufferStatus;
+using ::aidl::android::hardware::camera::device::ErrorMsg;
+using ::aidl::android::hardware::camera::device::StreamBufferRequestError;
+using ::aidl::android::hardware::camera::device::StreamBuffersVal;
+using ::aidl::android::hardware::graphics::common::PixelFormat;
+
+const int64_t kBufferReturnTimeoutSec = 1;
+
+DeviceCb::DeviceCb(CameraAidlTest* parent, camera_metadata_t* staticMeta) : mParent(parent) {
+    mStaticMetadata = staticMeta;
+}
+
+ScopedAStatus DeviceCb::notify(const std::vector<NotifyMsg>& msgs) {
+    std::vector<std::pair<bool, nsecs_t>> readoutTimestamps;
+
+    size_t count = msgs.size();
+    readoutTimestamps.resize(count);
+
+    for (size_t i = 0; i < count; i++) {
+        const NotifyMsg& msg = msgs[i];
+        switch (msg.getTag()) {
+            case NotifyMsg::Tag::error:
+                readoutTimestamps[i] = {false, 0};
+                break;
+            case NotifyMsg::Tag::shutter:
+                const auto& shutter = msg.get<NotifyMsg::Tag::shutter>();
+                readoutTimestamps[i] = {true, shutter.readoutTimestamp};
+                break;
+        }
+    }
+
+    return notifyHelper(msgs, readoutTimestamps);
+}
+
+ScopedAStatus DeviceCb::processCaptureResult(const std::vector<CaptureResult>& results) {
+    if (nullptr == mParent) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+
+    bool notify = false;
+    std::unique_lock<std::mutex> l(mParent->mLock);
+    for (const auto& result : results) {
+        notify = processCaptureResultLocked(result, result.physicalCameraMetadata);
+    }
+
+    l.unlock();
+    if (notify) {
+        mParent->mResultCondition.notify_one();
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ScopedAStatus DeviceCb::requestStreamBuffers(const std::vector<BufferRequest>& bufReqs,
+                                             std::vector<StreamBufferRet>* buffers,
+                                             BufferRequestStatus* _aidl_return) {
+    std::vector<StreamBufferRet>& bufRets = *buffers;
+    std::unique_lock<std::mutex> l(mLock);
+
+    if (!mUseHalBufManager) {
+        ALOGE("%s: Camera does not support HAL buffer management", __FUNCTION__);
+        ADD_FAILURE();
+        *_aidl_return = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
+        return ScopedAStatus::ok();
+    }
+
+    if (bufReqs.size() > mStreams.size()) {
+        ALOGE("%s: illegal buffer request: too many requests!", __FUNCTION__);
+        ADD_FAILURE();
+        *_aidl_return = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
+        return ndk::ScopedAStatus::ok();
+    }
+
+    std::vector<size_t> indexes(bufReqs.size());
+    for (size_t i = 0; i < bufReqs.size(); i++) {
+        bool found = false;
+        for (size_t idx = 0; idx < mStreams.size(); idx++) {
+            if (bufReqs[i].streamId == mStreams[idx].id) {
+                found = true;
+                indexes[i] = idx;
+                break;
+            }
+        }
+        if (!found) {
+            ALOGE("%s: illegal buffer request: unknown streamId %d!", __FUNCTION__,
+                  bufReqs[i].streamId);
+            ADD_FAILURE();
+            *_aidl_return = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
+            return ScopedAStatus::ok();
+        }
+    }
+
+    bool allStreamOk = true;
+    bool atLeastOneStreamOk = false;
+    bufRets.resize(bufReqs.size());
+
+    for (size_t i = 0; i < bufReqs.size(); i++) {
+        size_t idx = indexes[i];
+        const auto& stream = mStreams[idx];
+        const auto& halStream = mHalStreams[idx];
+        const BufferRequest& bufReq = bufReqs[i];
+
+        if (mOutstandingBufferIds[idx].size() + bufReq.numBuffersRequested > halStream.maxBuffers) {
+            bufRets[i].streamId = stream.id;
+            bufRets[i].val.set<StreamBuffersVal::Tag::error>(
+                    StreamBufferRequestError::MAX_BUFFER_EXCEEDED);
+            allStreamOk = false;
+            continue;
+        }
+
+        std::vector<StreamBuffer> tmpRetBuffers(bufReq.numBuffersRequested);
+        for (size_t j = 0; j < bufReq.numBuffersRequested; j++) {
+            buffer_handle_t handle;
+            uint32_t w = stream.width;
+            uint32_t h = stream.height;
+            if (stream.format == PixelFormat::BLOB) {
+                w = stream.bufferSize;
+                h = 1;
+            }
+
+            CameraAidlTest::allocateGraphicBuffer(
+                    w, h,
+                    android_convertGralloc1To0Usage(static_cast<uint64_t>(halStream.producerUsage),
+                                                    static_cast<uint64_t>(halStream.consumerUsage)),
+                    halStream.overrideFormat, &handle);
+
+            StreamBuffer streamBuffer = StreamBuffer();
+            StreamBuffer& sb = tmpRetBuffers[j];
+            sb = {
+                    stream.id,        mNextBufferId,  ::android::dupToAidl(handle),
+                    BufferStatus::OK, NativeHandle(), NativeHandle(),
+            };
+
+            mOutstandingBufferIds[idx][mNextBufferId++] = ::android::dupToAidl(handle);
+        }
+        atLeastOneStreamOk = true;
+        bufRets[i].streamId = stream.id;
+        bufRets[i].val.set<StreamBuffersVal::Tag::buffers>(std::move(tmpRetBuffers));
+    }
+
+    if (allStreamOk) {
+        *_aidl_return = BufferRequestStatus::OK;
+    } else if (atLeastOneStreamOk) {
+        *_aidl_return = BufferRequestStatus::FAILED_PARTIAL;
+    } else {
+        *_aidl_return = BufferRequestStatus::FAILED_UNKNOWN;
+    }
+
+    if (!hasOutstandingBuffersLocked()) {
+        l.unlock();
+        mFlushedCondition.notify_one();
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ScopedAStatus DeviceCb::returnStreamBuffers(const std::vector<StreamBuffer>& buffers) {
+    if (!mUseHalBufManager) {
+        ALOGE("%s: Camera does not support HAL buffer management", __FUNCTION__);
+        ADD_FAILURE();
+    }
+
+    std::unique_lock<std::mutex> l(mLock);
+    for (const auto& buf : buffers) {
+        if (buf.bufferId == 0) {
+            // Don't return buffers of bufId 0 (empty buffer)
+            continue;
+        }
+        bool found = false;
+        for (size_t idx = 0; idx < mOutstandingBufferIds.size(); idx++) {
+            if (mStreams[idx].id == buf.streamId &&
+                mOutstandingBufferIds[idx].count(buf.bufferId) == 1) {
+                mOutstandingBufferIds[idx].erase(buf.bufferId);
+                // TODO: check do we need to close/delete native handle or assume we have enough
+                // memory to run till the test finish? since we do not capture much requests (and
+                // most of time one buffer is sufficient)
+                found = true;
+                break;
+            }
+        }
+        if (found) {
+            continue;
+        }
+        ALOGE("%s: unknown buffer ID %" PRIu64, __FUNCTION__, buf.bufferId);
+        ADD_FAILURE();
+    }
+    if (!hasOutstandingBuffersLocked()) {
+        l.unlock();
+        mFlushedCondition.notify_one();
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+void DeviceCb::setCurrentStreamConfig(const std::vector<Stream>& streams,
+                                      const std::vector<HalStream>& halStreams) {
+    ASSERT_EQ(streams.size(), halStreams.size());
+    ASSERT_NE(streams.size(), 0);
+    for (size_t i = 0; i < streams.size(); i++) {
+        ASSERT_EQ(streams[i].id, halStreams[i].id);
+    }
+    std::lock_guard<std::mutex> l(mLock);
+    mUseHalBufManager = true;
+    mStreams = streams;
+    mHalStreams = halStreams;
+    mOutstandingBufferIds.clear();
+    for (size_t i = 0; i < streams.size(); i++) {
+        mOutstandingBufferIds.emplace_back();
+    }
+}
+
+void DeviceCb::waitForBuffersReturned() {
+    std::unique_lock<std::mutex> lk(mLock);
+    if (hasOutstandingBuffersLocked()) {
+        auto timeout = std::chrono::seconds(kBufferReturnTimeoutSec);
+        auto st = mFlushedCondition.wait_for(lk, timeout);
+        ASSERT_NE(std::cv_status::timeout, st);
+    }
+}
+
+bool DeviceCb::processCaptureResultLocked(
+        const CaptureResult& results, std::vector<PhysicalCameraMetadata> physicalCameraMetadata) {
+    bool notify = false;
+    uint32_t frameNumber = results.frameNumber;
+
+    if ((results.result.metadata.empty()) && (results.outputBuffers.empty()) &&
+        (results.inputBuffer.buffer.fds.empty()) && (results.fmqResultSize == 0)) {
+        ALOGE("%s: No result data provided by HAL for frame %d result count: %d", __func__,
+              frameNumber, (int)results.fmqResultSize);
+        ADD_FAILURE();
+        return notify;
+    }
+
+    auto requestEntry = mParent->mInflightMap.find(frameNumber);
+    if (requestEntry == mParent->mInflightMap.end()) {
+        ALOGE("%s: Unexpected frame number! received: %u", __func__, frameNumber);
+        ADD_FAILURE();
+        return notify;
+    }
+
+    bool isPartialResult = false;
+    bool hasInputBufferInRequest = false;
+    auto& request = requestEntry->second;
+
+    CameraMetadata resultMetadata;
+    size_t resultSize = 0;
+    if (results.fmqResultSize > 0) {
+        resultMetadata.metadata.resize(results.fmqResultSize);
+        if (request->resultQueue == nullptr) {
+            ADD_FAILURE();
+            return notify;
+        }
+
+        if (!request->resultQueue->read(reinterpret_cast<int8_t*>(resultMetadata.metadata.data()),
+                                        results.fmqResultSize)) {
+            ALOGE("%s: Frame %d: Cannot read camera metadata from fmq,"
+                  "size = %" PRIu64,
+                  __func__, frameNumber, results.fmqResultSize);
+            ADD_FAILURE();
+            return notify;
+        }
+
+        // Physical device results are only expected in the last/final
+        // partial result notification.
+        bool expectPhysicalResults = !(request->usePartialResult &&
+                                       (results.partialResult < request->numPartialResults));
+        if (expectPhysicalResults &&
+            (physicalCameraMetadata.size() != request->expectedPhysicalResults.size())) {
+            ALOGE("%s: Frame %d: Returned physical metadata count %zu "
+                  "must be equal to expected count %zu",
+                  __func__, frameNumber, physicalCameraMetadata.size(),
+                  request->expectedPhysicalResults.size());
+            ADD_FAILURE();
+            return notify;
+        }
+        std::vector<std::vector<uint8_t>> physResultMetadata;
+        physResultMetadata.resize(physicalCameraMetadata.size());
+        for (size_t i = 0; i < physicalCameraMetadata.size(); i++) {
+            physResultMetadata[i].resize(physicalCameraMetadata[i].fmqMetadataSize);
+            if (!request->resultQueue->read(reinterpret_cast<int8_t*>(physResultMetadata[i].data()),
+                                            physicalCameraMetadata[i].fmqMetadataSize)) {
+                ALOGE("%s: Frame %d: Cannot read physical camera metadata from fmq,"
+                      "size = %" PRIu64,
+                      __func__, frameNumber, physicalCameraMetadata[i].fmqMetadataSize);
+                ADD_FAILURE();
+                return notify;
+            }
+        }
+        resultSize = resultMetadata.metadata.size();
+    } else if (!results.result.metadata.empty()) {
+        resultMetadata = results.result;
+        resultSize = resultMetadata.metadata.size();
+    }
+
+    if (!request->usePartialResult && (resultSize > 0) && (results.partialResult != 1)) {
+        ALOGE("%s: Result is malformed for frame %d: partial_result %u "
+              "must be 1  if partial result is not supported",
+              __func__, frameNumber, results.partialResult);
+        ADD_FAILURE();
+        return notify;
+    }
+
+    if (results.partialResult != 0) {
+        request->partialResultCount = results.partialResult;
+    }
+
+    // Check if this result carries only partial metadata
+    if (request->usePartialResult && (resultSize > 0)) {
+        if ((results.partialResult > request->numPartialResults) || (results.partialResult < 1)) {
+            ALOGE("%s: Result is malformed for frame %d: partial_result %u"
+                  " must be  in the range of [1, %d] when metadata is "
+                  "included in the result",
+                  __func__, frameNumber, results.partialResult, request->numPartialResults);
+            ADD_FAILURE();
+            return notify;
+        }
+
+        // Verify no duplicate tags between partial results
+        const camera_metadata_t* partialMetadata =
+                reinterpret_cast<const camera_metadata_t*>(resultMetadata.metadata.data());
+        const camera_metadata_t* collectedMetadata = request->collectedResult.getAndLock();
+        camera_metadata_ro_entry_t searchEntry, foundEntry;
+        for (size_t i = 0; i < get_camera_metadata_entry_count(partialMetadata); i++) {
+            if (0 != get_camera_metadata_ro_entry(partialMetadata, i, &searchEntry)) {
+                ADD_FAILURE();
+                request->collectedResult.unlock(collectedMetadata);
+                return notify;
+            }
+            if (-ENOENT !=
+                find_camera_metadata_ro_entry(collectedMetadata, searchEntry.tag, &foundEntry)) {
+                ADD_FAILURE();
+                request->collectedResult.unlock(collectedMetadata);
+                return notify;
+            }
+        }
+        request->collectedResult.unlock(collectedMetadata);
+        request->collectedResult.append(partialMetadata);
+
+        isPartialResult = (results.partialResult < request->numPartialResults);
+    } else if (resultSize > 0) {
+        request->collectedResult.append(
+                reinterpret_cast<const camera_metadata_t*>(resultMetadata.metadata.data()));
+        isPartialResult = false;
+    }
+
+    hasInputBufferInRequest = request->hasInputBuffer;
+
+    // Did we get the (final) result metadata for this capture?
+    if ((resultSize > 0) && !isPartialResult) {
+        if (request->haveResultMetadata) {
+            ALOGE("%s: Called multiple times with metadata for frame %d", __func__, frameNumber);
+            ADD_FAILURE();
+            return notify;
+        }
+        request->haveResultMetadata = true;
+        request->collectedResult.sort();
+
+        // Verify final result metadata
+        camera_metadata_t* staticMetadataBuffer = mStaticMetadata;
+        bool isMonochrome = Status::OK == CameraAidlTest::isMonochromeCamera(staticMetadataBuffer);
+        if (isMonochrome) {
+            CameraAidlTest::verifyMonochromeCameraResult(request->collectedResult);
+        }
+
+        // Verify logical camera result metadata
+        bool isLogicalCamera =
+                Status::OK == CameraAidlTest::isLogicalMultiCamera(staticMetadataBuffer);
+        if (isLogicalCamera) {
+            camera_metadata_t* collectedMetadata =
+                    const_cast<camera_metadata_t*>(request->collectedResult.getAndLock());
+            uint8_t* rawMetadata = reinterpret_cast<uint8_t*>(collectedMetadata);
+            std::vector metadata = std::vector(
+                    rawMetadata, rawMetadata + get_camera_metadata_size(collectedMetadata));
+            CameraAidlTest::verifyLogicalCameraResult(staticMetadataBuffer, metadata);
+            request->collectedResult.unlock(collectedMetadata);
+        }
+    }
+
+    uint32_t numBuffersReturned = results.outputBuffers.size();
+    auto& inputBuffer = results.inputBuffer.buffer;
+    if (!inputBuffer.fds.empty() && !inputBuffer.ints.empty()) {
+        if (hasInputBufferInRequest) {
+            numBuffersReturned += 1;
+        } else {
+            ALOGW("%s: Input buffer should be NULL if there is no input"
+                  " buffer sent in the request",
+                  __func__);
+        }
+    }
+    request->numBuffersLeft -= numBuffersReturned;
+    if (request->numBuffersLeft < 0) {
+        ALOGE("%s: Too many buffers returned for frame %d", __func__, frameNumber);
+        ADD_FAILURE();
+        return notify;
+    }
+
+    for (const auto& buffer : results.outputBuffers) {
+        // wait for the fence timestamp and store it along with the buffer
+        // TODO: Check if we really need the dup here
+        android::sp<android::Fence> releaseFence = nullptr;
+        if (buffer.releaseFence.fds.size() == 1 && buffer.releaseFence.fds[0].get() >= 0) {
+            releaseFence = new android::Fence(dup(buffer.releaseFence.fds[0].get()));
+        }
+
+        CameraAidlTest::InFlightRequest::StreamBufferAndTimestamp streamBufferAndTimestamp;
+        streamBufferAndTimestamp.buffer = {buffer.streamId,
+                                           buffer.bufferId,
+                                           ::android::makeFromAidl(buffer.buffer),
+                                           buffer.status,
+                                           ::android::makeFromAidl(buffer.acquireFence),
+                                           ::android::makeFromAidl(buffer.releaseFence)};
+        streamBufferAndTimestamp.timeStamp = systemTime();
+        if (releaseFence && releaseFence->isValid()) {
+            releaseFence->wait(/*ms*/ 300);
+            nsecs_t releaseTime = releaseFence->getSignalTime();
+            if (streamBufferAndTimestamp.timeStamp < releaseTime)
+                streamBufferAndTimestamp.timeStamp = releaseTime;
+        }
+        request->resultOutputBuffers.push_back(streamBufferAndTimestamp);
+    }
+    // If shutter event is received notify the pending threads.
+    if (request->shutterTimestamp != 0) {
+        notify = true;
+    }
+
+    if (mUseHalBufManager) {
+        returnStreamBuffers(results.outputBuffers);
+    }
+    return notify;
+}
+
+ScopedAStatus DeviceCb::notifyHelper(
+        const std::vector<NotifyMsg>& msgs,
+        const std::vector<std::pair<bool, nsecs_t>>& readoutTimestamps) {
+    std::lock_guard<std::mutex> l(mParent->mLock);
+
+    for (size_t i = 0; i < msgs.size(); i++) {
+        const NotifyMsg& msg = msgs[i];
+        NotifyMsg::Tag msgTag = msgs[i].getTag();
+        switch (msgTag) {
+            case NotifyMsg::Tag::error:
+                if (ErrorCode::ERROR_DEVICE == msg.get<NotifyMsg::Tag::error>().errorCode) {
+                    ALOGE("%s: Camera reported serious device error", __func__);
+                    ADD_FAILURE();
+                } else {
+                    auto itr = mParent->mInflightMap.find(
+                            msg.get<NotifyMsg::Tag::error>().frameNumber);
+                    if (itr == mParent->mInflightMap.end()) {
+                        ALOGE("%s: Unexpected error frame number! received: %u", __func__,
+                              msg.get<NotifyMsg::Tag::error>().frameNumber);
+                        ADD_FAILURE();
+                        break;
+                    }
+
+                    auto r = itr->second;
+                    if (ErrorCode::ERROR_RESULT == msg.get<NotifyMsg::Tag::error>().errorCode &&
+                        msg.get<NotifyMsg::Tag::error>().errorStreamId != -1) {
+                        if (r->haveResultMetadata) {
+                            ALOGE("%s: Camera must report physical camera result error before "
+                                  "the final capture result!",
+                                  __func__);
+                            ADD_FAILURE();
+                        } else {
+                            for (auto& mStream : mStreams) {
+                                if (mStream.id == msg.get<NotifyMsg::Tag::error>().errorStreamId) {
+                                    std::string physicalCameraId = mStream.physicalCameraId;
+                                    bool idExpected =
+                                            r->expectedPhysicalResults.find(physicalCameraId) !=
+                                            r->expectedPhysicalResults.end();
+                                    if (!idExpected) {
+                                        ALOGE("%s: ERROR_RESULT's error stream's physicalCameraId "
+                                              "%s must be expected",
+                                              __func__, physicalCameraId.c_str());
+                                        ADD_FAILURE();
+                                    } else {
+                                        r->expectedPhysicalResults.erase(physicalCameraId);
+                                    }
+                                    break;
+                                }
+                            }
+                        }
+                    } else {
+                        r->errorCodeValid = true;
+                        r->errorCode = msg.get<NotifyMsg::Tag::error>().errorCode;
+                        r->errorStreamId = msg.get<NotifyMsg::Tag::error>().errorStreamId;
+                    }
+                }
+                break;
+            case NotifyMsg::Tag::shutter:
+                auto itr =
+                        mParent->mInflightMap.find(msg.get<NotifyMsg::Tag::shutter>().frameNumber);
+                if (itr == mParent->mInflightMap.end()) {
+                    ALOGE("%s: Unexpected shutter frame number! received: %u", __func__,
+                          msg.get<NotifyMsg::Tag::shutter>().frameNumber);
+                    ADD_FAILURE();
+                    break;
+                }
+                auto& r = itr->second;
+                r->shutterTimestamp = msg.get<NotifyMsg::Tag::shutter>().timestamp;
+                r->shutterReadoutTimestampValid = readoutTimestamps[i].first;
+                r->shutterReadoutTimestamp = readoutTimestamps[i].second;
+                break;
+        }
+    }
+
+    mParent->mResultCondition.notify_one();
+    return ScopedAStatus::ok();
+}
+
+bool DeviceCb::hasOutstandingBuffersLocked() {
+    if (!mUseHalBufManager) {
+        return false;
+    }
+    for (const auto& outstandingBuffers : mOutstandingBufferIds) {
+        if (!outstandingBuffers.empty()) {
+            return true;
+        }
+    }
+    return false;
+}
diff --git a/camera/provider/aidl/vts/device_cb.h b/camera/provider/aidl/vts/device_cb.h
new file mode 100644
index 0000000..82ca10d
--- /dev/null
+++ b/camera/provider/aidl/vts/device_cb.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_DEVICECB_H_
+#define HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_DEVICECB_H_
+
+#include <camera_aidl_test.h>
+
+#include <unordered_map>
+
+#include <CameraMetadata.h>
+#include <aidl/android/hardware/camera/device/BnCameraDeviceCallback.h>
+#include <aidl/android/hardware/camera/device/NotifyMsg.h>
+
+using ::aidl::android::hardware::camera::device::BnCameraDeviceCallback;
+using ::aidl::android::hardware::camera::device::BufferRequest;
+using ::aidl::android::hardware::camera::device::BufferRequestStatus;
+using ::aidl::android::hardware::camera::device::CaptureResult;
+using ::aidl::android::hardware::camera::device::HalStream;
+using ::aidl::android::hardware::camera::device::NotifyMsg;
+using ::aidl::android::hardware::camera::device::PhysicalCameraMetadata;
+using ::aidl::android::hardware::camera::device::Stream;
+using ::aidl::android::hardware::camera::device::StreamBuffer;
+using ::aidl::android::hardware::camera::device::StreamBufferRet;
+using ::aidl::android::hardware::common::NativeHandle;
+
+using ::ndk::ScopedAStatus;
+
+class CameraAidlTest;
+
+class DeviceCb : public BnCameraDeviceCallback {
+  public:
+    DeviceCb(CameraAidlTest* parent, camera_metadata_t* staticMeta);
+    ScopedAStatus notify(const std::vector<NotifyMsg>& msgs) override;
+    ScopedAStatus processCaptureResult(const std::vector<CaptureResult>& results) override;
+    ScopedAStatus requestStreamBuffers(const std::vector<BufferRequest>& bufReqs,
+                                       std::vector<StreamBufferRet>* buffers,
+                                       BufferRequestStatus* _aidl_return) override;
+    ScopedAStatus returnStreamBuffers(const std::vector<StreamBuffer>& buffers) override;
+
+    void setCurrentStreamConfig(const std::vector<Stream>& streams,
+                                const std::vector<HalStream>& halStreams);
+
+    void waitForBuffersReturned();
+
+  private:
+    bool processCaptureResultLocked(const CaptureResult& results,
+                                    std::vector<PhysicalCameraMetadata> physicalCameraMetadata);
+    ScopedAStatus notifyHelper(const std::vector<NotifyMsg>& msgs,
+                               const std::vector<std::pair<bool, nsecs_t>>& readoutTimestamps);
+
+    CameraAidlTest* mParent;  // Parent object
+
+    camera_metadata_t* mStaticMetadata;
+    bool hasOutstandingBuffersLocked();
+
+    /* members for requestStreamBuffers() and returnStreamBuffers()*/
+    std::mutex mLock;  // protecting members below
+    bool mUseHalBufManager = false;
+    std::vector<Stream> mStreams;
+    std::vector<HalStream> mHalStreams;
+    int64_t mNextBufferId = 1;
+    using OutstandingBuffers = std::unordered_map<uint64_t, NativeHandle>;
+    // size == mStreams.size(). Tracking each streams outstanding buffers
+    std::vector<OutstandingBuffers> mOutstandingBufferIds;
+    std::condition_variable mFlushedCondition;
+};
+
+#endif  // HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_DEVICECB_H_
diff --git a/camera/provider/aidl/vts/empty_device_cb.cpp b/camera/provider/aidl/vts/empty_device_cb.cpp
new file mode 100644
index 0000000..38b0d4c
--- /dev/null
+++ b/camera/provider/aidl/vts/empty_device_cb.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "empty_device_cb.h"
+#include <log/log.h>
+
+ScopedAStatus EmptyDeviceCb::notify(const std::vector<NotifyMsg>&) {
+    ALOGI("notify callback");
+    ADD_FAILURE();  // Empty callback should not reach here
+    return ndk::ScopedAStatus::ok();
+}
+ScopedAStatus EmptyDeviceCb::processCaptureResult(const std::vector<CaptureResult>&) {
+    ALOGI("processCaptureResult callback");
+    ADD_FAILURE();  // Empty callback should not reach here
+    return ndk::ScopedAStatus::ok();
+}
+ScopedAStatus EmptyDeviceCb::requestStreamBuffers(const std::vector<BufferRequest>&,
+                                                  std::vector<StreamBufferRet>*,
+                                                  BufferRequestStatus* _aidl_return) {
+    ALOGI("requestStreamBuffers callback");
+    // HAL might want to request buffer after configureStreams, but tests with EmptyDeviceCb
+    // doesn't actually need to send capture requests, so just return an error.
+    *_aidl_return = BufferRequestStatus::FAILED_UNKNOWN;
+    return ndk::ScopedAStatus::ok();
+}
+ScopedAStatus EmptyDeviceCb::returnStreamBuffers(const std::vector<StreamBuffer>&) {
+    ALOGI("returnStreamBuffers");
+    ADD_FAILURE();  // Empty callback should not reach here
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/camera/provider/aidl/vts/empty_device_cb.h b/camera/provider/aidl/vts/empty_device_cb.h
new file mode 100644
index 0000000..e777513
--- /dev/null
+++ b/camera/provider/aidl/vts/empty_device_cb.h
@@ -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.
+ */
+
+#ifndef HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_EMPTY_DEVICE_CB_H_
+#define HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_EMPTY_DEVICE_CB_H_
+
+#include <aidl/android/hardware/camera/device/BnCameraDeviceCallback.h>
+#include <gtest/gtest.h>
+
+using namespace ::aidl::android::hardware::camera::device;
+
+using ::aidl::android::hardware::camera::device::BnCameraDeviceCallback;
+using ::ndk::ScopedAStatus;
+
+class EmptyDeviceCb : public BnCameraDeviceCallback {
+  public:
+    ScopedAStatus notify(const std::vector<NotifyMsg>& msgs) override;
+    ScopedAStatus processCaptureResult(const std::vector<::CaptureResult>& results) override;
+    ScopedAStatus requestStreamBuffers(const std::vector<BufferRequest>& bufReqs,
+                                       std::vector<StreamBufferRet>* buffers,
+                                       BufferRequestStatus* _aidl_return) override;
+    ScopedAStatus returnStreamBuffers(const std::vector<StreamBuffer>& buffers) override;
+};
+
+#endif  // HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_EMPTY_DEVICE_CB_H_
diff --git a/camera/provider/aidl/vts/simple_device_cb.cpp b/camera/provider/aidl/vts/simple_device_cb.cpp
new file mode 100644
index 0000000..e9a2c73
--- /dev/null
+++ b/camera/provider/aidl/vts/simple_device_cb.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "simple_device_cb.h"
+
+ScopedAStatus SimpleDeviceCb::notify(const std::vector<NotifyMsg>& msgs) {
+    std::unique_lock<std::mutex> l(mParent->mLock);
+    mParent->mNotifyMessages = msgs;
+    mParent->mResultCondition.notify_one();
+
+    return ndk::ScopedAStatus::ok();
+}
+ScopedAStatus SimpleDeviceCb::processCaptureResult(const std::vector<CaptureResult>&) {
+    return ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION);
+}
+ScopedAStatus SimpleDeviceCb::requestStreamBuffers(const std::vector<BufferRequest>&,
+                                                   std::vector<StreamBufferRet>*,
+                                                   BufferRequestStatus*) {
+    return ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION);
+}
+ScopedAStatus SimpleDeviceCb::returnStreamBuffers(const std::vector<StreamBuffer>&) {
+    return ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION);
+}
diff --git a/camera/provider/aidl/vts/simple_device_cb.h b/camera/provider/aidl/vts/simple_device_cb.h
new file mode 100644
index 0000000..6beffc7
--- /dev/null
+++ b/camera/provider/aidl/vts/simple_device_cb.h
@@ -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.
+ */
+
+#ifndef HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_SIMPLE_DEVICE_CB_H_
+#define HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_SIMPLE_DEVICE_CB_H_
+
+#include "camera_aidl_test.h"
+
+#include <unordered_map>
+
+#include <aidl/android/hardware/camera/device/BnCameraDeviceCallback.h>
+
+using namespace ::aidl::android::hardware::camera::device;
+
+class SimpleDeviceCb : public BnCameraDeviceCallback {
+  public:
+    ScopedAStatus notify(const std::vector<NotifyMsg>& msgs) override;
+    ScopedAStatus processCaptureResult(const std::vector<CaptureResult>& results) override;
+    ScopedAStatus requestStreamBuffers(const std::vector<BufferRequest>& bufReqs,
+                                       std::vector<StreamBufferRet>* buffers,
+                                       BufferRequestStatus* _aidl_return) override;
+    virtual ScopedAStatus returnStreamBuffers(const std::vector<StreamBuffer>& buffers) override;
+
+  private:
+    CameraAidlTest* mParent;
+};
+
+#endif  // HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_SIMPLE_DEVICE_CB_H_
diff --git a/camera/provider/aidl/vts/torch_provider_cb.cpp b/camera/provider/aidl/vts/torch_provider_cb.cpp
new file mode 100644
index 0000000..52240df
--- /dev/null
+++ b/camera/provider/aidl/vts/torch_provider_cb.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.
+ */
+
+#include "torch_provider_cb.h"
+
+TorchProviderCb::TorchProviderCb(CameraAidlTest* parent) {
+    mParent = parent;
+}
+
+ndk::ScopedAStatus TorchProviderCb::torchModeStatusChange(const std::string&,
+                                                          TorchModeStatus newStatus) {
+    std::lock_guard<std::mutex> l(mParent->mTorchLock);
+    mParent->mTorchStatus = newStatus;
+    mParent->mTorchCond.notify_one();
+    return ndk::ScopedAStatus::ok();
+}
+ScopedAStatus TorchProviderCb::cameraDeviceStatusChange(
+        const std::string&, ::aidl::android::hardware::camera::common::CameraDeviceStatus) {
+    // Should not be called
+    return ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION);
+}
+ScopedAStatus TorchProviderCb::physicalCameraDeviceStatusChange(
+        const std::string&, const std::string&,
+        ::aidl::android::hardware::camera::common::CameraDeviceStatus) {
+    // Should not be called
+    return ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION);
+}
diff --git a/camera/provider/aidl/vts/torch_provider_cb.h b/camera/provider/aidl/vts/torch_provider_cb.h
new file mode 100644
index 0000000..0353254
--- /dev/null
+++ b/camera/provider/aidl/vts/torch_provider_cb.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_TORCH_PROVIDER_CB_H_
+#define HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_TORCH_PROVIDER_CB_H_
+
+#import <aidl/android/hardware/camera/provider/BnCameraProviderCallback.h>
+#import <camera_aidl_test.h>
+
+using ::aidl::android::hardware::camera::common::TorchModeStatus;
+using ::aidl::android::hardware::camera::provider::BnCameraProviderCallback;
+
+class TorchProviderCb : public BnCameraProviderCallback {
+  public:
+    TorchProviderCb(CameraAidlTest* parent);
+    ndk::ScopedAStatus torchModeStatusChange(const std::string& cameraDeviceName,
+                                             TorchModeStatus newStatus) override;
+
+    ScopedAStatus cameraDeviceStatusChange(
+            const std::string& in_cameraDeviceName,
+            ::aidl::android::hardware::camera::common::CameraDeviceStatus in_newStatus) override;
+
+    ScopedAStatus physicalCameraDeviceStatusChange(
+            const std::string& in_cameraDeviceName, const std::string& in_physicalCameraDeviceName,
+            ::aidl::android::hardware::camera::common::CameraDeviceStatus in_newStatus) override;
+
+  private:
+    CameraAidlTest* mParent;
+};
+
+#endif  // HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_TORCH_PROVIDER_CB_H_
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 7bdc60d..8b3830a 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -140,14 +140,6 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.bluetooth.audio</name>
-        <version>2.0-2</version>
-        <interface>
-            <name>IBluetoothAudioProvidersFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.bluetooth.audio</name>
         <interface>
@@ -222,10 +214,6 @@
         <name>android.hardware.drm</name>
         <version>1</version>
         <interface>
-            <name>ICryptoFactory</name>
-            <regex-instance>.*</regex-instance>
-        </interface>
-        <interface>
             <name>IDrmFactory</name>
             <regex-instance>.*</regex-instance>
         </interface>
@@ -528,6 +516,14 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.radio.config</name>
+        <version>1</version>
+        <interface>
+            <name>IRadioConfig</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.radio.data</name>
         <version>1</version>
         <interface>
@@ -589,16 +585,6 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.radio</name>
-        <version>1.6</version>
-        <interface>
-            <name>IRadio</name>
-            <instance>slot1</instance>
-            <instance>slot2</instance>
-            <instance>slot3</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.radio</name>
         <version>1.2</version>
         <interface>
             <name>ISap</name>
@@ -606,33 +592,6 @@
         </interface>
     </hal>
     <hal format="hidl" optional="true">
-        <name>android.hardware.radio.config</name>
-        <!--
-        See compatibility_matrix.4.xml on versioning of radio config HAL.
-        -->
-        <version>1.1</version>
-        <interface>
-            <name>IRadioConfig</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="aidl" optional="true">
-        <name>android.hardware.radio.config</name>
-        <version>1</version>
-        <interface>
-            <name>IRadioConfig</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.radio.config</name>
-        <version>1.3</version>
-        <interface>
-            <name>IRadioConfig</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
         <name>android.hardware.renderscript</name>
         <version>1.0</version>
         <interface>
diff --git a/current.txt b/current.txt
index 1fedaa0..df6f91d 100644
--- a/current.txt
+++ b/current.txt
@@ -910,5 +910,6 @@
 d0fb32f3ddeb9af7115ab32905225ea69b930d2472be8e9610f0cf136c15aefb android.hardware.keymaster@4.0::IKeymasterDevice # b/210424594
 ca62a2a95d173ed323309e5e00f653ad3cceec82a6e5e4976a249cb5aafe2515 android.hardware.neuralnetworks@1.2::types
 fa76bced6b1b71c40fc706c508a9011284c57f57831cd0cf5f45653ed4ea463e android.hardware.neuralnetworks@1.3::types
+700d9de9b47984898789f5706e59285ea6fe83aa5744dccf8491c4b881033ae7 android.hardware.camera.device@3.7::ICameraInjectionSession
 
 # There should be no more HIDL HALs - please use AIDL instead.
diff --git a/drm/1.0/vts/functional/Android.bp b/drm/1.0/vts/functional/Android.bp
index a35d41d..d6c37c5 100644
--- a/drm/1.0/vts/functional/Android.bp
+++ b/drm/1.0/vts/functional/Android.bp
@@ -53,6 +53,10 @@
     local_include_dirs: [
         "include",
     ],
+    tidy_timeout_srcs: [
+        "drm_hal_clearkey_test.cpp",
+        "drm_hal_vendor_test.cpp",
+    ],
     srcs: [
         "drm_hal_clearkey_test.cpp",
         "drm_hal_vendor_test.cpp",
diff --git a/drm/1.1/vts/functional/Android.bp b/drm/1.1/vts/functional/Android.bp
index 656ec50..760b67e 100644
--- a/drm/1.1/vts/functional/Android.bp
+++ b/drm/1.1/vts/functional/Android.bp
@@ -32,6 +32,9 @@
     local_include_dirs: [
         "include",
     ],
+    tidy_timeout_srcs: [
+        "drm_hal_clearkey_test.cpp",
+    ],
     srcs: [
         "drm_hal_clearkey_test.cpp",
     ],
diff --git a/drm/1.2/vts/functional/Android.bp b/drm/1.2/vts/functional/Android.bp
index 5a655e7..9a45051 100644
--- a/drm/1.2/vts/functional/Android.bp
+++ b/drm/1.2/vts/functional/Android.bp
@@ -42,6 +42,9 @@
     local_include_dirs: [
         "include",
     ],
+    tidy_timeout_srcs: [
+        "drm_hal_test.cpp",
+    ],
     srcs: [
         "drm_hal_clearkey_module.cpp",
         "drm_hal_common.cpp",
diff --git a/drm/aidl/OWNERS b/drm/aidl/OWNERS
new file mode 100644
index 0000000..fa8fd20
--- /dev/null
+++ b/drm/aidl/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 49079
+edwinwong@google.com
+kelzhan@google.com
+robertshih@google.com
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/CryptoSchemes.aidl
similarity index 90%
rename from drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl
rename to drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/CryptoSchemes.aidl
index d2b48d2..1d3c293 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/CryptoSchemes.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@
 
 package android.hardware.drm;
 @VintfStability
-parcelable DecryptResult {
-  int bytesWritten;
-  String detailedError;
+parcelable CryptoSchemes {
+  List<android.hardware.drm.Uuid> uuids;
+  List<android.hardware.drm.SupportedContentType> mimeTypes;
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptArgs.aidl
similarity index 82%
copy from drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl
copy to drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptArgs.aidl
index d2b48d2..9c574a4 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptArgs.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -33,7 +33,14 @@
 
 package android.hardware.drm;
 @VintfStability
-parcelable DecryptResult {
-  int bytesWritten;
-  String detailedError;
+parcelable DecryptArgs {
+  boolean secure;
+  byte[] keyId;
+  byte[] iv;
+  android.hardware.drm.Mode mode;
+  android.hardware.drm.Pattern pattern;
+  android.hardware.drm.SubSample[] subSamples;
+  android.hardware.drm.SharedBuffer source;
+  long offset;
+  android.hardware.drm.DestinationBuffer destination;
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DestinationBuffer.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DestinationBuffer.aidl
index 4f2d133..8c3ba7d 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DestinationBuffer.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DestinationBuffer.aidl
@@ -33,8 +33,7 @@
 
 package android.hardware.drm;
 @VintfStability
-parcelable DestinationBuffer {
-  android.hardware.drm.BufferType type;
+union DestinationBuffer {
   android.hardware.drm.SharedBuffer nonsecureMemory;
   android.hardware.common.NativeHandle secureMemory;
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ICryptoFactory.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ICryptoFactory.aidl
deleted file mode 100644
index 0d4296e..0000000
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ICryptoFactory.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.hardware.drm;
-@VintfStability
-interface ICryptoFactory {
-  @nullable android.hardware.drm.ICryptoPlugin createPlugin(in android.hardware.drm.Uuid uuid, in byte[] initData);
-  boolean isCryptoSchemeSupported(in android.hardware.drm.Uuid uuid);
-}
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ICryptoPlugin.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ICryptoPlugin.aidl
index 2224795..31c45e0 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ICryptoPlugin.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/ICryptoPlugin.aidl
@@ -34,10 +34,10 @@
 package android.hardware.drm;
 @VintfStability
 interface ICryptoPlugin {
-  android.hardware.drm.DecryptResult decrypt(in boolean secure, in byte[] keyId, in byte[] iv, in android.hardware.drm.Mode mode, in android.hardware.drm.Pattern pattern, in android.hardware.drm.SubSample[] subSamples, in android.hardware.drm.SharedBuffer source, in long offset, in android.hardware.drm.DestinationBuffer destination);
+  int decrypt(in android.hardware.drm.DecryptArgs args);
   List<android.hardware.drm.LogMessage> getLogMessages();
   void notifyResolution(in int width, in int height);
   boolean requiresSecureDecoderComponent(in String mime);
   void setMediaDrmSession(in byte[] sessionId);
-  void setSharedBufferBase(in android.hardware.common.Ashmem base, in int bufferId);
+  void setSharedBufferBase(in android.hardware.drm.SharedBuffer base);
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/IDrmFactory.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/IDrmFactory.aidl
index af48737..82efbb7 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/IDrmFactory.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/IDrmFactory.aidl
@@ -34,8 +34,7 @@
 package android.hardware.drm;
 @VintfStability
 interface IDrmFactory {
-  @nullable android.hardware.drm.IDrmPlugin createPlugin(in android.hardware.drm.Uuid uuid, in String appPackageName);
-  List<android.hardware.drm.Uuid> getSupportedCryptoSchemes();
-  boolean isContentTypeSupported(in String mimeType);
-  boolean isCryptoSchemeSupported(in android.hardware.drm.Uuid uuid, in String mimeType, in android.hardware.drm.SecurityLevel securityLevel);
+  @nullable android.hardware.drm.IDrmPlugin createDrmPlugin(in android.hardware.drm.Uuid uuid, in String appPackageName);
+  @nullable android.hardware.drm.ICryptoPlugin createCryptoPlugin(in android.hardware.drm.Uuid uuid, in byte[] initData);
+  android.hardware.drm.CryptoSchemes getSupportedCryptoSchemes();
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/IDrmPlugin.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/IDrmPlugin.aidl
index 5f839d7..ae10062 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/IDrmPlugin.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/IDrmPlugin.aidl
@@ -63,7 +63,6 @@
   void removeOfflineLicense(in android.hardware.drm.KeySetId keySetId);
   void removeSecureStop(in android.hardware.drm.SecureStopId secureStopId);
   boolean requiresSecureDecoder(in String mime, in android.hardware.drm.SecurityLevel level);
-  boolean requiresSecureDecoderDefault(in String mime);
   void restoreKeys(in byte[] sessionId, in android.hardware.drm.KeySetId keySetId);
   void setCipherAlgorithm(in byte[] sessionId, in String algorithm);
   void setListener(in android.hardware.drm.IDrmPluginListener listener);
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl
index e88d388..261516f 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl
@@ -36,8 +36,8 @@
 enum KeyStatusType {
   USABLE = 0,
   EXPIRED = 1,
-  OUTPUTNOTALLOWED = 2,
-  STATUSPENDING = 3,
-  INTERNALERROR = 4,
-  USABLEINFUTURE = 5,
+  OUTPUT_NOT_ALLOWED = 2,
+  STATUS_PENDING = 3,
+  INTERNAL_ERROR = 4,
+  USABLE_IN_FUTURE = 5,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SharedBuffer.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SharedBuffer.aidl
index 973ef0d..314fe7c 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SharedBuffer.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SharedBuffer.aidl
@@ -37,4 +37,5 @@
   int bufferId;
   long offset;
   long size;
+  android.hardware.common.NativeHandle handle;
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SupportedContentType.aidl
similarity index 89%
copy from drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl
copy to drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SupportedContentType.aidl
index d2b48d2..6ef5db8 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SupportedContentType.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -33,7 +33,8 @@
 
 package android.hardware.drm;
 @VintfStability
-parcelable DecryptResult {
-  int bytesWritten;
-  String detailedError;
+parcelable SupportedContentType {
+  String mime;
+  android.hardware.drm.SecurityLevel minLevel;
+  android.hardware.drm.SecurityLevel maxLevel;
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Uuid.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Uuid.aidl
index ec2eb16..3c2cfa20 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Uuid.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Uuid.aidl
@@ -34,5 +34,5 @@
 package android.hardware.drm;
 @VintfStability
 parcelable Uuid {
-  byte[] uuid;
+  byte[16] uuid;
 }
diff --git a/drm/aidl/android/hardware/drm/DecryptResult.aidl b/drm/aidl/android/hardware/drm/CryptoSchemes.aidl
similarity index 64%
rename from drm/aidl/android/hardware/drm/DecryptResult.aidl
rename to drm/aidl/android/hardware/drm/CryptoSchemes.aidl
index 17e939b..1f251d8 100644
--- a/drm/aidl/android/hardware/drm/DecryptResult.aidl
+++ b/drm/aidl/android/hardware/drm/CryptoSchemes.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,18 +16,20 @@
 
 package android.hardware.drm;
 
-/**
- * The DecryptResult parcelable contains the result of
- * ICryptoPlugin decrypt method.
- */
+import android.hardware.drm.SupportedContentType;
+import android.hardware.drm.Uuid;
+
 @VintfStability
-parcelable DecryptResult {
-    /** The number of decrypted bytes. */
-    int bytesWritten;
+parcelable CryptoSchemes {
 
     /**
-     * Vendor-specific error message if provided by the vendor's
-     * crypto HAL.
+     * Supported crypto schemes
      */
-    String detailedError;
+    List<Uuid> uuids;
+
+    /**
+     * Supported mime types, and supported SecurityLevels for each mime
+     */
+    List<SupportedContentType> mimeTypes;
+
 }
diff --git a/drm/aidl/android/hardware/drm/DecryptArgs.aidl b/drm/aidl/android/hardware/drm/DecryptArgs.aidl
new file mode 100644
index 0000000..5ec1b71
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/DecryptArgs.aidl
@@ -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.
+ */
+
+package android.hardware.drm;
+
+import android.hardware.drm.DestinationBuffer;
+import android.hardware.drm.KeyStatusType;
+import android.hardware.drm.Mode;
+import android.hardware.drm.Pattern;
+import android.hardware.drm.SharedBuffer;
+import android.hardware.drm.SubSample;
+
+/**
+ * Arguments to ICryptoPlugin decrypt
+ */
+@VintfStability
+parcelable DecryptArgs {
+
+    /**
+     * A flag to indicate if a secure decoder is being used.
+     *
+     * This enables the plugin to configure buffer modes to work consistently
+     * with a secure decoder.
+     */
+    boolean secure;
+
+    /**
+     * The keyId for the key that is used to do the decryption.
+     *
+     * The keyId refers to a key in the associated MediaDrm instance.
+     */
+    byte[] keyId;
+
+    /**
+     * The initialization vector
+     */
+    byte[] iv;
+
+    /**
+     * Crypto mode
+     */
+    Mode mode;
+
+    /**
+     * Crypto pattern
+     */
+    Pattern pattern;
+
+    /**
+     * A vector of subsamples indicating the number of clear and encrypted
+     * bytes to process.
+     *
+     * This allows the decrypt call to operate on a range of subsamples in a
+     * single call
+     */
+    SubSample[] subSamples;
+
+    /**
+     * Input buffer for the decryption
+     */
+    SharedBuffer source;
+
+    /**
+     * The offset of the first byte of encrypted data from the base of the
+     * source buffer
+     */
+    long offset;
+
+    /**
+     * Output buffer for the decryption
+     */
+    DestinationBuffer destination;
+
+}
diff --git a/drm/aidl/android/hardware/drm/DestinationBuffer.aidl b/drm/aidl/android/hardware/drm/DestinationBuffer.aidl
index 0f1e3f5..7fc61e1 100644
--- a/drm/aidl/android/hardware/drm/DestinationBuffer.aidl
+++ b/drm/aidl/android/hardware/drm/DestinationBuffer.aidl
@@ -17,29 +17,24 @@
 package android.hardware.drm;
 
 import android.hardware.common.NativeHandle;
-import android.hardware.drm.BufferType;
 import android.hardware.drm.SharedBuffer;
 
 /**
  * A decrypt destination buffer can be either normal user-space shared
  * memory for the non-secure decrypt case, or it can be a secure buffer
- * which is referenced by a native-handle. The native handle is allocated
- * by the vendor's buffer allocator.
+ * which is referenced by a native-handle.
+ *
+ * The native handle is allocated by the vendor's buffer allocator.
  */
 @VintfStability
-parcelable DestinationBuffer {
+union DestinationBuffer {
     /**
-     * The type of the buffer
-     */
-    BufferType type;
-    /**
-     * If type == SHARED_MEMORY, the decrypted data must be written
-     * to user-space non-secure shared memory.
+     * decrypted data written to user-space non-secure shared memory.
      */
     SharedBuffer nonsecureMemory;
     /**
-     * If type == NATIVE_HANDLE, the decrypted data must be written
-     * to secure memory referenced by the vendor's buffer allocator.
+     * decrypted data written to secure memory referenced by the vendor's
+     * buffer allocator.
      */
     NativeHandle secureMemory;
 }
diff --git a/drm/aidl/android/hardware/drm/ICryptoFactory.aidl b/drm/aidl/android/hardware/drm/ICryptoFactory.aidl
deleted file mode 100644
index 202bd3d..0000000
--- a/drm/aidl/android/hardware/drm/ICryptoFactory.aidl
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.drm;
-
-import android.hardware.drm.Uuid;
-
-/**
- * ICryptoFactory is the main entry point for interacting with a vendor's
- * crypto HAL to create crypto plugins.
-
- * Crypto plugins create crypto sessions which are used by a codec to decrypt
- * protected video content.
- */
-@VintfStability
-interface ICryptoFactory {
-    /**
-     * Create a crypto plugin for the specified uuid and scheme-specific
-     * initialization data.
-     *
-     * @param uuid uniquely identifies the drm scheme. See
-     *     http://dashif.org/identifiers/protection for uuid assignments
-     *
-     * @param initData scheme-specific init data.
-     *
-     * @return A crypto plugin instance if successful, or null if not created.
-     */
-    @nullable android.hardware.drm.ICryptoPlugin createPlugin(
-            in Uuid uuid, in byte[] initData);
-
-    /**
-     * Determine if a crypto scheme is supported by this HAL.
-     *
-     * @param uuid identifies the crypto scheme in question
-     * @return must be true only if the scheme is supported
-     */
-    boolean isCryptoSchemeSupported(in Uuid uuid);
-}
diff --git a/drm/aidl/android/hardware/drm/ICryptoPlugin.aidl b/drm/aidl/android/hardware/drm/ICryptoPlugin.aidl
index 80a63df..d344b62 100644
--- a/drm/aidl/android/hardware/drm/ICryptoPlugin.aidl
+++ b/drm/aidl/android/hardware/drm/ICryptoPlugin.aidl
@@ -17,7 +17,7 @@
 package android.hardware.drm;
 
 import android.hardware.common.Ashmem;
-import android.hardware.drm.DecryptResult;
+import android.hardware.drm.DecryptArgs;
 import android.hardware.drm.DestinationBuffer;
 import android.hardware.drm.LogMessage;
 import android.hardware.drm.Mode;
@@ -38,23 +38,7 @@
      * Decrypt an array of subsamples from the source memory buffer to the
      * destination memory buffer.
      *
-     * @param secure a flag to indicate if a secure decoder is being used.
-     *     This enables the plugin to configure buffer modes to work
-     *     consistently with a secure decoder.
-     * @param the keyId for the key that is used to do the decryption. The
-     *     keyId refers to a key in the associated MediaDrm instance.
-     * @param iv the initialization vector to use
-     * @param mode the crypto mode to use
-     * @param pattern the crypto pattern to use
-     * @param subSamples a vector of subsamples indicating the number
-     *     of clear and encrypted bytes to process. This allows the decrypt
-     *     call to operate on a range of subsamples in a single call
-     * @param source the input buffer for the decryption
-     * @param offset the offset of the first byte of encrypted data from
-     *     the base of the source buffer
-     * @param destination the output buffer for the decryption
-     *
-     * @return DecryptResult parcelable
+     * @return number of decrypted bytes
      *     Implicit error codes:
      *       + ERROR_DRM_CANNOT_HANDLE in other failure cases
      *       + ERROR_DRM_DECRYPT if the decrypt operation fails
@@ -74,9 +58,7 @@
      *       + ERROR_DRM_SESSION_NOT_OPENED if the decrypt session is not
      *             opened
      */
-    DecryptResult decrypt(in boolean secure, in byte[] keyId, in byte[] iv, in Mode mode,
-            in Pattern pattern, in SubSample[] subSamples, in SharedBuffer source, in long offset,
-            in DestinationBuffer destination);
+    int decrypt(in DecryptArgs args);
 
     /**
      * Get OEMCrypto or plugin error messages.
@@ -129,10 +111,8 @@
      * There can be multiple shared buffers per crypto plugin. The buffers
      * are distinguished by the bufferId.
      *
-     * @param base the base of the memory buffer identified by
-     *     bufferId
-     * @param bufferId identifies the specific shared buffer for which
-     *     the base is being set.
+     * @param base the base of the memory buffer abstracted by
+     *     SharedBuffer parcelable (bufferId, size, handle)
      */
-    void setSharedBufferBase(in Ashmem base, in int bufferId);
+    void setSharedBufferBase(in SharedBuffer base);
 }
diff --git a/drm/aidl/android/hardware/drm/IDrmFactory.aidl b/drm/aidl/android/hardware/drm/IDrmFactory.aidl
index b9622a4..86c3f21 100644
--- a/drm/aidl/android/hardware/drm/IDrmFactory.aidl
+++ b/drm/aidl/android/hardware/drm/IDrmFactory.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.drm;
 
+import android.hardware.drm.CryptoSchemes;
 import android.hardware.drm.SecurityLevel;
 import android.hardware.drm.Uuid;
 
@@ -40,37 +41,30 @@
      *     Implicit error codes:
      *       + ERROR_DRM_CANNOT_HANDLE if the plugin cannot be created.
      */
-    @nullable android.hardware.drm.IDrmPlugin createPlugin(
+    @nullable android.hardware.drm.IDrmPlugin createDrmPlugin(
             in Uuid uuid, in String appPackageName);
 
     /**
+     * Create a crypto plugin for the specified uuid and scheme-specific
+     * initialization data.
+     *
+     * @param uuid uniquely identifies the drm scheme. See
+     *     http://dashif.org/identifiers/protection for uuid assignments
+     *
+     * @param initData scheme-specific init data.
+     *
+     * @return A crypto plugin instance if successful, or null if not created.
+     */
+    @nullable android.hardware.drm.ICryptoPlugin createCryptoPlugin(
+            in Uuid uuid, in byte[] initData);
+
+    /**
      * Return vector of uuids identifying crypto schemes supported by
      * this HAL.
      *
      * @return List of uuids for which isCryptoSchemeSupported is true;
      *      each uuid can be used as input to createPlugin.
      */
-    List<Uuid> getSupportedCryptoSchemes();
+    CryptoSchemes getSupportedCryptoSchemes();
 
-    /**
-     * Determine if the HAL factory is able to construct plugins that
-     * support a given media container format specified by mimeType
-     *
-     * @param mimeType identifies the mime type in question
-     *
-     * @return must be true only if the scheme is supported
-     */
-    boolean isContentTypeSupported(in String mimeType);
-
-    /**
-     * Determine if a specific security level is supported by the device.
-     *
-     * @param uuid identifies the crypto scheme in question
-     * @param mimeType identifies the mime type in question
-     * @param securityLevel specifies the security level required
-     *
-     * @return must be true only if the scheme is supported
-     */
-    boolean isCryptoSchemeSupported(
-            in Uuid uuid, in String mimeType, in SecurityLevel securityLevel);
 }
diff --git a/drm/aidl/android/hardware/drm/IDrmPlugin.aidl b/drm/aidl/android/hardware/drm/IDrmPlugin.aidl
index e649f26..11ca8b6 100644
--- a/drm/aidl/android/hardware/drm/IDrmPlugin.aidl
+++ b/drm/aidl/android/hardware/drm/IDrmPlugin.aidl
@@ -577,17 +577,6 @@
     boolean requiresSecureDecoder(in String mime, in SecurityLevel level);
 
     /**
-     * Check if the specified mime-type requires a secure decoder component
-     * at the highest security level supported on the device.
-     *
-     * @param mime The content mime-type
-     *
-     * @return must be true if and only if a secure decoder is required
-     *     for the specified mime-type
-     */
-    boolean requiresSecureDecoderDefault(in String mime);
-
-    /**
      * Restore persisted offline keys into a new session
      *
      * @param sessionId the session id the call applies to
diff --git a/drm/aidl/android/hardware/drm/KeyStatusType.aidl b/drm/aidl/android/hardware/drm/KeyStatusType.aidl
index 6902d87..6c3c6a2 100644
--- a/drm/aidl/android/hardware/drm/KeyStatusType.aidl
+++ b/drm/aidl/android/hardware/drm/KeyStatusType.aidl
@@ -32,20 +32,20 @@
      * The key is not currently usable to decrypt media data because its output
      * requirements cannot currently be met.
      */
-    OUTPUTNOTALLOWED,
+    OUTPUT_NOT_ALLOWED,
     /**
      * The status of the key is not yet known and is being determined.
      */
-    STATUSPENDING,
+    STATUS_PENDING,
     /**
      * The key is not currently usable to decrypt media data because of an
      * internal error in processing unrelated to input parameters.
      */
-    INTERNALERROR,
+    INTERNAL_ERROR,
     /**
      * The key is not yet usable to decrypt media because the start
      * time is in the future. The key must become usable when
      * its start time is reached.
      */
-    USABLEINFUTURE,
+    USABLE_IN_FUTURE,
 }
diff --git a/drm/aidl/android/hardware/drm/SharedBuffer.aidl b/drm/aidl/android/hardware/drm/SharedBuffer.aidl
index 6977284..2b2610f 100644
--- a/drm/aidl/android/hardware/drm/SharedBuffer.aidl
+++ b/drm/aidl/android/hardware/drm/SharedBuffer.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.drm;
 
+import android.hardware.common.NativeHandle;
+
 /**
  * SharedBuffer describes a decrypt buffer which is defined by a bufferId, an
  * offset and a size.  The offset is relative to the shared memory base for the
@@ -36,4 +38,8 @@
      * The size of the shared buffer in bytes
      */
     long size;
+    /**
+     * Handle to shared memory
+     */
+    NativeHandle handle;
 }
diff --git a/drm/aidl/android/hardware/drm/BufferType.aidl b/drm/aidl/android/hardware/drm/SupportedContentType.aidl
similarity index 62%
rename from drm/aidl/android/hardware/drm/BufferType.aidl
rename to drm/aidl/android/hardware/drm/SupportedContentType.aidl
index 089c950..f4fabad 100644
--- a/drm/aidl/android/hardware/drm/BufferType.aidl
+++ b/drm/aidl/android/hardware/drm/SupportedContentType.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,9 +16,16 @@
 
 package android.hardware.drm;
 
+import android.hardware.drm.SecurityLevel;
+
 @VintfStability
-@Backing(type="int")
-enum BufferType {
-    SHARED_MEMORY = 0,
-    NATIVE_HANDLE = 1,
+parcelable SupportedContentType {
+    /** Supported mime type. E.g. cenc, video/mp4, etc */
+    String mime;
+
+    /** Minimum supported security level (inclusive) */
+    SecurityLevel minLevel;
+
+    /** Maximum supported security level (inclusive) */
+    SecurityLevel maxLevel;
 }
diff --git a/drm/aidl/android/hardware/drm/Uuid.aidl b/drm/aidl/android/hardware/drm/Uuid.aidl
index b36c409..db5a70d 100644
--- a/drm/aidl/android/hardware/drm/Uuid.aidl
+++ b/drm/aidl/android/hardware/drm/Uuid.aidl
@@ -18,5 +18,5 @@
 
 @VintfStability
 parcelable Uuid {
-    byte[] uuid;
+    byte[16] uuid;
 }
diff --git a/drm/aidl/vts/Android.bp b/drm/aidl/vts/Android.bp
index 5b41830..190f60d 100644
--- a/drm/aidl/vts/Android.bp
+++ b/drm/aidl/vts/Android.bp
@@ -49,6 +49,8 @@
         "android.hardware.drm@1.0-helper",
         "android.hardware.drm-V1-ndk",
         "android.hardware.common-V2-ndk",
+        "libaidlcommonsupport",
+        "libgmock_ndk",
         "libdrmvtshelper",
         "libvtsclearkey",
     ],
diff --git a/drm/aidl/vts/drm_hal_common.cpp b/drm/aidl/vts/drm_hal_common.cpp
index 751c25b..de7dc28 100644
--- a/drm/aidl/vts/drm_hal_common.cpp
+++ b/drm/aidl/vts/drm_hal_common.cpp
@@ -22,9 +22,11 @@
 #include <sys/mman.h>
 #include <random>
 
+#include <aidlcommonsupport/NativeHandle.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 #include <android/sharedmem.h>
+#include <cutils/native_handle.h>
 
 #include "drm_hal_clearkey_module.h"
 #include "drm_hal_common.h"
@@ -39,8 +41,7 @@
 
 using std::vector;
 using ::aidl::android::hardware::common::Ashmem;
-using ::aidl::android::hardware::drm::BufferType;
-using ::aidl::android::hardware::drm::DecryptResult;
+using ::aidl::android::hardware::drm::DecryptArgs;
 using ::aidl::android::hardware::drm::DestinationBuffer;
 using ::aidl::android::hardware::drm::EventType;
 using ::aidl::android::hardware::drm::ICryptoPlugin;
@@ -72,7 +73,6 @@
 }
 
 const char* kDrmIface = "android.hardware.drm.IDrmFactory";
-const char* kCryptoIface = "android.hardware.drm.ICryptoFactory";
 
 std::string HalFullName(const std::string& iface, const std::string& basename) {
     return iface + '/' + basename;
@@ -184,7 +184,6 @@
           test_info->name(), GetParamService().c_str());
 
     auto svc = GetParamService();
-    const string cryptoInstance = HalFullName(kCryptoIface, svc);
     const string drmInstance = HalFullName(kDrmIface, svc);
 
     if (drmInstance.find("IDrmFactory") != std::string::npos) {
@@ -192,12 +191,6 @@
                 ::ndk::SpAIBinder(AServiceManager_waitForService(drmInstance.c_str())));
         ASSERT_NE(drmFactory, nullptr);
         drmPlugin = createDrmPlugin();
-    }
-
-    if (cryptoInstance.find("ICryptoFactory") != std::string::npos) {
-        cryptoFactory = ICryptoFactory::fromBinder(
-                ::ndk::SpAIBinder(AServiceManager_waitForService(cryptoInstance.c_str())));
-        ASSERT_NE(cryptoFactory, nullptr);
         cryptoPlugin = createCryptoPlugin();
     }
 
@@ -211,14 +204,12 @@
     contentConfigurations = vendorModule->getContentConfigurations();
 
     // If drm scheme not installed skip subsequent tests
-    bool result = false;
-    drmFactory->isCryptoSchemeSupported({getUUID()}, "cenc", SecurityLevel::SW_SECURE_CRYPTO,
-                                        &result);
+    bool result = isCryptoSchemeSupported(getAidlUUID(), SecurityLevel::SW_SECURE_CRYPTO, "cenc");
     if (!result) {
         if (GetParamUUID() == std::array<uint8_t, 16>()) {
             GTEST_SKIP() << "vendor module drm scheme not supported";
         } else {
-            FAIL() << "param scheme must not supported";
+            FAIL() << "param scheme must be supported";
         }
     }
 
@@ -234,18 +225,18 @@
     }
     std::string packageName("aidl.android.hardware.drm.test");
     std::shared_ptr<::aidl::android::hardware::drm::IDrmPlugin> result;
-    auto ret = drmFactory->createPlugin({getUUID()}, packageName, &result);
+    auto ret = drmFactory->createDrmPlugin(getAidlUUID(), packageName, &result);
     EXPECT_OK(ret) << "createDrmPlugin remote call failed";
     return result;
 }
 
 std::shared_ptr<::aidl::android::hardware::drm::ICryptoPlugin> DrmHalTest::createCryptoPlugin() {
-    if (cryptoFactory == nullptr) {
+    if (drmFactory == nullptr) {
         return nullptr;
     }
     vector<uint8_t> initVec;
     std::shared_ptr<::aidl::android::hardware::drm::ICryptoPlugin> result;
-    auto ret = cryptoFactory->createPlugin({getUUID()}, initVec, &result);
+    auto ret = drmFactory->createCryptoPlugin(getAidlUUID(), initVec, &result);
     EXPECT_OK(ret) << "createCryptoPlugin remote call failed";
     return result;
 }
@@ -265,11 +256,36 @@
 std::vector<uint8_t> DrmHalTest::getVendorUUID() {
     if (vendorModule == nullptr) {
         ALOGW("vendor module for %s not found", GetParamService().c_str());
-        return {};
+        return std::vector<uint8_t>(16);
     }
     return vendorModule->getUUID();
 }
 
+bool DrmHalTest::isCryptoSchemeSupported(Uuid uuid, SecurityLevel level, std::string mime) {
+    CryptoSchemes schemes{};
+    auto ret = drmFactory->getSupportedCryptoSchemes(&schemes);
+    EXPECT_OK(ret);
+    if (!ret.isOk() || !std::count(schemes.uuids.begin(), schemes.uuids.end(), uuid)) {
+        return false;
+    }
+    if (mime.empty()) {
+        EXPECT_THAT(level, AnyOf(Eq(SecurityLevel::DEFAULT), Eq(SecurityLevel::UNKNOWN)));
+        return true;
+    }
+    for (auto ct : schemes.mimeTypes) {
+        if (ct.mime != mime) {
+            continue;
+        }
+        if (level == SecurityLevel::DEFAULT || level == SecurityLevel::UNKNOWN) {
+            return true;
+        }
+        if (level <= ct.maxLevel && level >= ct.minLevel) {
+            return true;
+        }
+    }
+    return false;
+}
+
 void DrmHalTest::provision() {
     std::string certificateType;
     std::string certificateAuthority;
@@ -410,38 +426,43 @@
 
 /**
  * getDecryptMemory allocates memory for decryption, then sets it
- * as a shared buffer base in the crypto hal.  A parcelable Ashmem
- * is returned.
+ * as a shared buffer base in the crypto hal. An output SharedBuffer
+ * is updated via reference.
  *
  * @param size the size of the memory segment to allocate
  * @param the index of the memory segment which will be used
  * to refer to it for decryption.
  */
-Ashmem DrmHalTest::getDecryptMemory(size_t size, size_t index) {
+void DrmHalTest::getDecryptMemory(size_t size, size_t index, SharedBuffer& out) {
+    out.bufferId = static_cast<int32_t>(index);
+    out.offset = 0;
+    out.size = static_cast<int64_t>(size);
+
     int fd = ASharedMemory_create("drmVtsSharedMemory", size);
     EXPECT_GE(fd, 0);
     EXPECT_EQ(size, ASharedMemory_getSize(fd));
+    auto handle = native_handle_create(1, 0);
+    handle->data[0] = fd;
+    out.handle = ::android::makeToAidl(handle);
 
-    Ashmem ashmem;
-    ashmem.fd = ::ndk::ScopedFileDescriptor(fd);
-    ashmem.size = size;
-    EXPECT_OK(cryptoPlugin->setSharedBufferBase(ashmem, index));
-    return ashmem;
+    EXPECT_OK(cryptoPlugin->setSharedBufferBase(out));
+    native_handle_delete(handle);
 }
 
-void DrmHalTest::fillRandom(const Ashmem& ashmem) {
+uint8_t* DrmHalTest::fillRandom(const ::aidl::android::hardware::drm::SharedBuffer& buf) {
     std::random_device rd;
     std::mt19937 rand(rd());
 
-    ::ndk::ScopedFileDescriptor fd = ashmem.fd.dup();
-    size_t size = ashmem.size;
+    auto fd = buf.handle.fds[0].get();
+    size_t size = buf.size;
     uint8_t* base = static_cast<uint8_t*>(
-            mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0));
+            mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
     EXPECT_NE(MAP_FAILED, base);
     for (size_t i = 0; i < size / sizeof(uint32_t); i++) {
         auto p = static_cast<uint32_t*>(static_cast<void*>(base));
         p[i] = rand();
     }
+    return base;
 }
 
 uint32_t DrmHalTest::decrypt(Mode mode, bool isSecure, const std::array<uint8_t, 16>& keyId,
@@ -453,6 +474,7 @@
     uint8_t localIv[AES_BLOCK_SIZE];
     memcpy(localIv, iv, AES_BLOCK_SIZE);
     vector<uint8_t> ivVec(localIv, localIv + AES_BLOCK_SIZE);
+    vector<uint8_t> keyIdVec(keyId.begin(), keyId.end());
 
     int64_t totalSize = 0;
     for (size_t i = 0; i < subSamples.size(); i++) {
@@ -463,32 +485,39 @@
     // The first totalSize bytes of shared memory is the encrypted
     // input, the second totalSize bytes (if exists) is the decrypted output.
     size_t factor = expectedStatus == Status::ERROR_DRM_FRAME_TOO_LARGE ? 1 : 2;
-    Ashmem sharedMemory = getDecryptMemory(totalSize * factor, kSegmentIndex);
+    SharedBuffer sourceBuffer;
+    getDecryptMemory(totalSize * factor, kSegmentIndex, sourceBuffer);
+    auto base = fillRandom(sourceBuffer);
 
-    const SharedBuffer sourceBuffer = {.bufferId = kSegmentIndex, .offset = 0, .size = totalSize};
-    fillRandom(sharedMemory);
+    SharedBuffer sourceRange;
+    sourceRange.bufferId = kSegmentIndex;
+    sourceRange.offset = 0;
+    sourceRange.size = totalSize;
 
-    const DestinationBuffer destBuffer = {
-            .type = BufferType::SHARED_MEMORY,
-            .nonsecureMemory = {.bufferId = kSegmentIndex, .offset = totalSize, .size = totalSize},
-            .secureMemory = {.fds = {}, .ints = {}}};
-    const uint64_t offset = 0;
-    uint32_t bytesWritten = 0;
-    vector<uint8_t> keyIdVec(keyId.begin(), keyId.end());
-    DecryptResult result;
-    auto ret = cryptoPlugin->decrypt(isSecure, keyIdVec, ivVec, mode, pattern, subSamples,
-                                     sourceBuffer, offset, destBuffer, &result);
+    SharedBuffer destRange;
+    destRange.bufferId = kSegmentIndex;
+    destRange.offset = totalSize;
+    destRange.size = totalSize;
+
+    DecryptArgs args;
+    args.secure = isSecure;
+    args.keyId = keyIdVec;
+    args.iv = ivVec;
+    args.mode = mode;
+    args.pattern = pattern;
+    args.subSamples = subSamples;
+    args.source = std::move(sourceRange);
+    args.offset = 0;
+    args.destination = std::move(destRange);
+
+    int32_t bytesWritten = 0;
+    auto ret = cryptoPlugin->decrypt(args, &bytesWritten);
     EXPECT_TXN(ret);
-    EXPECT_EQ(expectedStatus, DrmErr(ret)) << "Unexpected decrypt status " << result.detailedError;
-    bytesWritten = result.bytesWritten;
+    EXPECT_EQ(expectedStatus, DrmErr(ret)) << "Unexpected decrypt status " << ret.getMessage();
 
     if (bytesWritten != totalSize) {
         return bytesWritten;
     }
-    ::ndk::ScopedFileDescriptor fd = sharedMemory.fd.dup();
-    uint8_t* base = static_cast<uint8_t*>(
-            mmap(nullptr, totalSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0));
-    EXPECT_NE(MAP_FAILED, base);
 
     // generate reference vector
     vector<uint8_t> reference(totalSize);
@@ -513,6 +542,7 @@
     EXPECT_EQ(0, memcmp(static_cast<void*>(&reference[0]), static_cast<void*>(base + totalSize),
                         totalSize))
             << "decrypt data mismatch";
+    munmap(base, totalSize * factor);
     return totalSize;
 }
 
diff --git a/drm/aidl/vts/drm_hal_test.cpp b/drm/aidl/vts/drm_hal_test.cpp
index 3ac9f5c..14b3acf 100644
--- a/drm/aidl/vts/drm_hal_test.cpp
+++ b/drm/aidl/vts/drm_hal_test.cpp
@@ -66,11 +66,8 @@
  * Ensure drm factory supports module UUID Scheme
  */
 TEST_P(DrmHalTest, VendorUuidSupported) {
-    bool result = false;
-    auto ret =
-            drmFactory->isCryptoSchemeSupported(getAidlUUID(), kVideoMp4, kSwSecureCrypto, &result);
-    ALOGI("kVideoMp4 = %s res %d", kVideoMp4, static_cast<bool>(result));
-    EXPECT_OK(ret);
+    bool result = isCryptoSchemeSupported(getAidlUUID(), kSwSecureCrypto, kVideoMp4);
+    ALOGI("kVideoMp4 = %s res %d", kVideoMp4, result);
     EXPECT_TRUE(result);
 }
 
@@ -80,10 +77,7 @@
 TEST_P(DrmHalTest, InvalidPluginNotSupported) {
     const vector<uint8_t> kInvalidUUID = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
                                           0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
-    bool result = false;
-    auto ret = drmFactory->isCryptoSchemeSupported(toAidlUuid(kInvalidUUID), kVideoMp4,
-                                                   kSwSecureCrypto, &result);
-    EXPECT_OK(ret);
+    auto result = isCryptoSchemeSupported(toAidlUuid(kInvalidUUID), kSwSecureCrypto, kVideoMp4);
     EXPECT_FALSE(result);
 }
 
@@ -93,10 +87,7 @@
 TEST_P(DrmHalTest, EmptyPluginUUIDNotSupported) {
     vector<uint8_t> emptyUUID(16);
     memset(emptyUUID.data(), 0, 16);
-    bool result = false;
-    auto ret = drmFactory->isCryptoSchemeSupported(toAidlUuid(emptyUUID), kVideoMp4,
-                                                   kSwSecureCrypto, &result);
-    EXPECT_OK(ret);
+    auto result = isCryptoSchemeSupported(toAidlUuid(emptyUUID), kSwSecureCrypto, kVideoMp4);
     EXPECT_FALSE(result);
 }
 
@@ -104,14 +95,24 @@
  * Ensure drm factory doesn't support an invalid mime type
  */
 TEST_P(DrmHalTest, BadMimeNotSupported) {
-    bool result = false;
-    auto ret =
-            drmFactory->isCryptoSchemeSupported(getAidlUUID(), kBadMime, kSwSecureCrypto, &result);
-    EXPECT_OK(ret);
+    auto result = isCryptoSchemeSupported(getAidlUUID(), kSwSecureCrypto, kBadMime);
     EXPECT_FALSE(result);
 }
 
 /**
+ * getSupportedCryptoSchemes confidence check
+ */
+TEST_P(DrmHalTest, SupportedCryptoSchemes) {
+    aidl::android::hardware::drm::CryptoSchemes schemes{};
+    auto result = drmFactory->getSupportedCryptoSchemes(&schemes);
+    EXPECT_FALSE(schemes.uuids.empty());
+    for(auto ct : schemes.mimeTypes) {
+        EXPECT_LE(ct.minLevel, ct.maxLevel);
+    }
+    EXPECT_OK(result);
+}
+
+/**
  *  DrmPlugin tests
  */
 
@@ -380,9 +381,7 @@
  * Ensure clearkey drm factory doesn't support security level higher than supported
  */
 TEST_P(DrmHalClearkeyTest, BadLevelNotSupported) {
-    bool result = false;
-    auto ret = drmFactory->isCryptoSchemeSupported(getAidlUUID(), kVideoMp4, kHwSecureAll, &result);
-    EXPECT_OK(ret);
+    auto result = isCryptoSchemeSupported(getAidlUUID(), kHwSecureAll, kVideoMp4);
     EXPECT_FALSE(result);
 }
 
@@ -461,7 +460,7 @@
     const vector<KeyStatus> keyStatusList = {
             {{0xa, 0xb, 0xc}, KeyStatusType::USABLE},
             {{0xd, 0xe, 0xf}, KeyStatusType::EXPIRED},
-            {{0x0, 0x1, 0x2}, KeyStatusType::USABLEINFUTURE},
+            {{0x0, 0x1, 0x2}, KeyStatusType::USABLE_IN_FUTURE},
     };
     EXPECT_EQ(sessionId, args.sessionId);
     EXPECT_EQ(keyStatusList, args.keyStatusList);
diff --git a/drm/aidl/vts/drm_hal_test_main.cpp b/drm/aidl/vts/drm_hal_test_main.cpp
index dc0f6d7..833a51a 100644
--- a/drm/aidl/vts/drm_hal_test_main.cpp
+++ b/drm/aidl/vts/drm_hal_test_main.cpp
@@ -42,21 +42,15 @@
 using drm_vts::PrintParamInstanceToString;
 
 static const std::vector<DrmHalTestParam> getAllInstances() {
-    using ::aidl::android::hardware::drm::ICryptoFactory;
     using ::aidl::android::hardware::drm::IDrmFactory;
 
     std::vector<std::string> drmInstances =
             android::getAidlHalInstanceNames(IDrmFactory::descriptor);
-    std::vector<std::string> cryptoInstances =
-            android::getAidlHalInstanceNames(ICryptoFactory::descriptor);
 
     std::set<std::string> allInstances;
     for (auto svc : drmInstances) {
         allInstances.insert(HalBaseName(svc));
     }
-    for (auto svc : cryptoInstances) {
-        allInstances.insert(HalBaseName(svc));
-    }
 
     std::vector<DrmHalTestParam> allInstanceUuidCombos;
     auto noUUID = [](std::string s) { return DrmHalTestParam(s); };
diff --git a/drm/aidl/vts/include/drm_hal_common.h b/drm/aidl/vts/include/drm_hal_common.h
index 4aac48b..d493bed 100644
--- a/drm/aidl/vts/include/drm_hal_common.h
+++ b/drm/aidl/vts/include/drm_hal_common.h
@@ -18,14 +18,17 @@
 
 #include <aidl/android/hardware/common/Ashmem.h>
 #include <aidl/android/hardware/drm/BnDrmPluginListener.h>
-#include <aidl/android/hardware/drm/ICryptoFactory.h>
 #include <aidl/android/hardware/drm/ICryptoPlugin.h>
 #include <aidl/android/hardware/drm/IDrmFactory.h>
 #include <aidl/android/hardware/drm/IDrmPlugin.h>
 #include <aidl/android/hardware/drm/IDrmPluginListener.h>
 #include <aidl/android/hardware/drm/Status.h>
+#include <android/binder_auto_utils.h>
+
+#include <gmock/gmock.h>
 
 #include <array>
+#include <algorithm>
 #include <chrono>
 #include <future>
 #include <iostream>
@@ -35,8 +38,6 @@
 #include <utility>
 #include <vector>
 
-#include <android/binder_auto_utils.h>
-
 #include "VtsHalHidlTargetCallbackBase.h"
 #include "drm_hal_vendor_module_api.h"
 #include "drm_vts_helper.h"
@@ -58,6 +59,9 @@
 namespace drm {
 namespace vts {
 
+using ::testing::AnyOf;
+using ::testing::Eq;
+
 ::aidl::android::hardware::drm::Status DrmErr(const ::ndk::ScopedAStatus& ret);
 std::string HalBaseName(const std::string& fullname);
 std::string HalFullName(const std::string& iface, const std::string& basename);
@@ -80,11 +84,14 @@
     std::array<uint8_t, 16> GetParamUUID() { return GetParam().scheme_; }
     std::string GetParamService() { return GetParam().instance_; }
     ::aidl::android::hardware::drm::Uuid toAidlUuid(const std::vector<uint8_t>& in_uuid) {
-        ::aidl::android::hardware::drm::Uuid uuid;
-        uuid.uuid = in_uuid;
-        return uuid;
+        std::array<uint8_t, 16> a;
+        std::copy_n(in_uuid.begin(), a.size(), a.begin());
+        return {a};
     }
 
+    bool isCryptoSchemeSupported(::aidl::android::hardware::drm::Uuid uuid,
+                                 ::aidl::android::hardware::drm::SecurityLevel level,
+                                 std::string mime);
     void provision();
     SessionId openSession(::aidl::android::hardware::drm::SecurityLevel level,
                           ::aidl::android::hardware::drm::Status* err);
@@ -106,8 +113,8 @@
 
     KeyedVector toAidlKeyedVector(const std::map<std::string, std::string>& params);
     std::array<uint8_t, 16> toStdArray(const std::vector<uint8_t>& vec);
-    void fillRandom(const ::aidl::android::hardware::common::Ashmem& ashmem);
-    ::aidl::android::hardware::common::Ashmem getDecryptMemory(size_t size, size_t index);
+    uint8_t* fillRandom(const ::aidl::android::hardware::drm::SharedBuffer& buf);
+    void getDecryptMemory(size_t size, size_t index, SharedBuffer& buf);
 
     uint32_t decrypt(::aidl::android::hardware::drm::Mode mode, bool isSecure,
                      const std::array<uint8_t, 16>& keyId, uint8_t* iv,
@@ -123,7 +130,6 @@
                          const std::vector<uint8_t>& key);
 
     std::shared_ptr<::aidl::android::hardware::drm::IDrmFactory> drmFactory;
-    std::shared_ptr<::aidl::android::hardware::drm::ICryptoFactory> cryptoFactory;
     std::shared_ptr<::aidl::android::hardware::drm::IDrmPlugin> drmPlugin;
     std::shared_ptr<::aidl::android::hardware::drm::ICryptoPlugin> cryptoPlugin;
 
@@ -139,16 +145,13 @@
   public:
     virtual void SetUp() override {
         DrmHalTest::SetUp();
-        const std::vector<uint8_t> kClearKeyUUID = {0xE2, 0x71, 0x9D, 0x58, 0xA9, 0x85, 0xB3, 0xC9,
-                                                    0x78, 0x1A, 0xB0, 0x30, 0xAF, 0x78, 0xD3, 0x0E};
+        auto kClearKeyUUID = toAidlUuid({0xE2, 0x71, 0x9D, 0x58, 0xA9, 0x85, 0xB3, 0xC9,
+                                         0x78, 0x1A, 0xB0, 0x30, 0xAF, 0x78, 0xD3, 0x0E});
         static const std::string kMimeType = "video/mp4";
         static constexpr ::aidl::android::hardware::drm::SecurityLevel kSecurityLevel =
                 ::aidl::android::hardware::drm::SecurityLevel::SW_SECURE_CRYPTO;
 
-        bool drmClearkey = false;
-        auto ret = drmFactory->isCryptoSchemeSupported(toAidlUuid(kClearKeyUUID), kMimeType,
-                                                       kSecurityLevel, &drmClearkey);
-        if (!drmClearkey) {
+        if (!isCryptoSchemeSupported(kClearKeyUUID, kSecurityLevel, kMimeType)) {
             GTEST_SKIP() << "ClearKey not supported by " << GetParamService();
         }
     }
diff --git a/gnss/aidl/Android.bp b/gnss/aidl/Android.bp
index 4d9c5cc..cc7c4e9 100644
--- a/gnss/aidl/Android.bp
+++ b/gnss/aidl/Android.bp
@@ -42,5 +42,11 @@
             },
         },
     },
-    versions: ["1"],
+    versions_with_info: [
+        {
+            version: "1",
+            imports: [],
+        },
+    ],
+
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/BlocklistedSource.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/BlocklistedSource.aidl
index a4f0097..ccb2b28 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/BlocklistedSource.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/BlocklistedSource.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 parcelable BlocklistedSource {
   android.hardware.gnss.GnssConstellationType constellation = android.hardware.gnss.GnssConstellationType.UNKNOWN;
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/CorrelationVector.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/CorrelationVector.aidl
index b0848bb..b959003 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/CorrelationVector.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/CorrelationVector.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 parcelable CorrelationVector {
   double frequencyOffsetMps;
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/ElapsedRealtime.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/ElapsedRealtime.aidl
index 7d3baa4..559ed29 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/ElapsedRealtime.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/ElapsedRealtime.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 parcelable ElapsedRealtime {
   int flags;
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssClock.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssClock.aidl
index c54cc2c..a8454dd 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssClock.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssClock.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 parcelable GnssClock {
   int gnssClockFlags;
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssConstellationType.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssConstellationType.aidl
index c1fcfcc..fee2ef6 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssConstellationType.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssConstellationType.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @Backing(type="int") @VintfStability
 enum GnssConstellationType {
   UNKNOWN = 0,
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl
index 01a3b3a..31426f0 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 parcelable GnssData {
   android.hardware.gnss.GnssMeasurement[] measurements;
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssLocation.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssLocation.aidl
index 54c126c..ed9dcfa 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssLocation.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssLocation.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 parcelable GnssLocation {
   int gnssLocationFlags;
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMeasurement.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMeasurement.aidl
index 948c540..8a44887 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMeasurement.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMeasurement.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 parcelable GnssMeasurement {
   int flags;
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMultipathIndicator.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMultipathIndicator.aidl
index 24f45c4..62ade9c 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMultipathIndicator.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMultipathIndicator.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @Backing(type="int") @VintfStability
 enum GnssMultipathIndicator {
   UNKNOWN = 0,
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssPowerStats.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssPowerStats.aidl
index 670244f..c4a9e61 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssPowerStats.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssPowerStats.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 parcelable GnssPowerStats {
   android.hardware.gnss.ElapsedRealtime elapsedRealtime;
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssSignalType.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssSignalType.aidl
index c2a5b51..4a49547 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssSignalType.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssSignalType.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 parcelable GnssSignalType {
   android.hardware.gnss.GnssConstellationType constellation = android.hardware.gnss.GnssConstellationType.UNKNOWN;
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnss.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnss.aidl
index 1a69f33..639539a 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnss.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnss.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IAGnss {
   void setCallback(in android.hardware.gnss.IAGnssCallback callback);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssCallback.aidl
index 2a46f61..b2da8d9 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssCallback.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IAGnssCallback {
   void agnssStatusCb(in android.hardware.gnss.IAGnssCallback.AGnssType type, in android.hardware.gnss.IAGnssCallback.AGnssStatusValue status);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl
index 69fa32b..8930752 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRil.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IAGnssRil {
   void setCallback(in android.hardware.gnss.IAGnssRilCallback callback);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRilCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRilCallback.aidl
index 152b10a..3717026 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRilCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IAGnssRilCallback.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IAGnssRilCallback {
   void requestSetIdCb(in int setIdflag);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
index 5657434..0e6405e 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnss {
   void setCallback(in android.hardware.gnss.IGnssCallback callback);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfo.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfo.aidl
index 2734ac1..43ad328 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfo.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnssAntennaInfo {
   void setCallback(in android.hardware.gnss.IGnssAntennaInfoCallback callback);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfoCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfoCallback.aidl
index ada9707..eb6abe5 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfoCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssAntennaInfoCallback.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnssAntennaInfoCallback {
   void gnssAntennaInfoCb(in android.hardware.gnss.IGnssAntennaInfoCallback.GnssAntennaInfo[] gnssAntennaInfos);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatching.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatching.aidl
index e1beed3..d82aa1f 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatching.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatching.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnssBatching {
   void init(in android.hardware.gnss.IGnssBatchingCallback callback);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatchingCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatchingCallback.aidl
index 427137a..b12a8bd 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatchingCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssBatchingCallback.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnssBatchingCallback {
   void gnssLocationBatchCb(in android.hardware.gnss.GnssLocation[] locations);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl
index 957a75f..48c88f5 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnssCallback {
   void gnssSetCapabilitiesCb(in int capabilities);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.aidl
index 54cd022..1d6399e 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnssConfiguration {
   void setSuplVersion(in int version);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssDebug.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssDebug.aidl
index 8e4b5f2..591b533 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssDebug.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssDebug.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnssDebug {
   android.hardware.gnss.IGnssDebug.DebugData getDebugData();
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssGeofence.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssGeofence.aidl
index 50da5bf..5065ad4 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssGeofence.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssGeofence.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnssGeofence {
   void setCallback(in android.hardware.gnss.IGnssGeofenceCallback callback);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssGeofenceCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssGeofenceCallback.aidl
index 26482ea..df5dc2d 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssGeofenceCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssGeofenceCallback.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnssGeofenceCallback {
   void gnssGeofenceTransitionCb(in int geofenceId, in android.hardware.gnss.GnssLocation location, in int transition, in long timestampMillis);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementCallback.aidl
index 6e62617..624a7ae 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementCallback.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnssMeasurementCallback {
   void gnssMeasurementCb(in android.hardware.gnss.GnssData data);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl
index 9c4a54b..6fe6a6c 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnssMeasurementInterface {
   void setCallback(in android.hardware.gnss.IGnssMeasurementCallback callback, in boolean enableFullTracking, in boolean enableCorrVecOutputs);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssNavigationMessageCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssNavigationMessageCallback.aidl
index d513c15..c65cff2 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssNavigationMessageCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssNavigationMessageCallback.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnssNavigationMessageCallback {
   void gnssNavigationMessageCb(in android.hardware.gnss.IGnssNavigationMessageCallback.GnssNavigationMessage message);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssNavigationMessageInterface.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssNavigationMessageInterface.aidl
index 196e9b9..187773d 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssNavigationMessageInterface.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssNavigationMessageInterface.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnssNavigationMessageInterface {
   void setCallback(in android.hardware.gnss.IGnssNavigationMessageCallback callback);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndication.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndication.aidl
index fbf1f6f..f77dbff 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndication.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndication.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnssPowerIndication {
   void setCallback(in android.hardware.gnss.IGnssPowerIndicationCallback callback);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndicationCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndicationCallback.aidl
index bfa787e..d35c77f 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndicationCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndicationCallback.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnssPowerIndicationCallback {
   void setCapabilitiesCb(in int capabilities);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsds.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsds.aidl
index 526ecc8..3aee798 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsds.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsds.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnssPsds {
   void injectPsdsData(in android.hardware.gnss.PsdsType psdsType, in byte[] psdsData);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsdsCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsdsCallback.aidl
index 2205bc4..dadc9fb 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsdsCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsdsCallback.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 interface IGnssPsdsCallback {
   void downloadRequestCb(in android.hardware.gnss.PsdsType psdsType);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/PsdsType.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/PsdsType.aidl
index 727bb69..60b15d6 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/PsdsType.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/PsdsType.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @Backing(type="int") @VintfStability
 enum PsdsType {
   LONG_TERM = 1,
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatelliteClockInfo.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatelliteClockInfo.aidl
index ed23e63..05f7733 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatelliteClockInfo.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatelliteClockInfo.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 parcelable SatelliteClockInfo {
   double satHardwareCodeBiasMeters;
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePositionEcef.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePositionEcef.aidl
index e1a20c3..3d4f7ff 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePositionEcef.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePositionEcef.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 parcelable SatellitePositionEcef {
   double posXMeters;
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePvt.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePvt.aidl
index 21a2520..5fd411f 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePvt.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePvt.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 parcelable SatellitePvt {
   int flags;
@@ -40,10 +41,10 @@
   android.hardware.gnss.SatelliteClockInfo satClockInfo;
   double ionoDelayMeters;
   double tropoDelayMeters;
-  int TOC;
-  int IODC;
-  int TOE;
-  int IODE;
+  long timeOfClockSeconds;
+  int issueOfDataClock;
+  long timeOfEphemerisSeconds;
+  int issueOfDataEphemeris;
   android.hardware.gnss.SatellitePvt.SatelliteEphemerisSource ephemerisSource = android.hardware.gnss.SatellitePvt.SatelliteEphemerisSource.OTHER;
   const int HAS_POSITION_VELOCITY_CLOCK_INFO = 1;
   const int HAS_IONO = 2;
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatelliteVelocityEcef.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatelliteVelocityEcef.aidl
index a571048..94d0b34 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatelliteVelocityEcef.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatelliteVelocityEcef.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss;
+/* @hide */
 @VintfStability
 parcelable SatelliteVelocityEcef {
   double velXMps;
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
index c4cf13f..4126702 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss.measurement_corrections;
+/* @hide */
 @VintfStability
 interface IMeasurementCorrectionsCallback {
   void setCapabilitiesCb(in int capabilities);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl
index 5dc5596..bd30534 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss.measurement_corrections;
+/* @hide */
 @VintfStability
 interface IMeasurementCorrectionsInterface {
   void setCorrections(in android.hardware.gnss.measurement_corrections.MeasurementCorrections corrections);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl
index f32c8c2..35fd79e 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss.measurement_corrections;
+/* @hide */
 @VintfStability
 parcelable MeasurementCorrections {
   double latitudeDegrees;
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
index 90c3818..90c9e03 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
@@ -32,10 +32,11 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss.measurement_corrections;
+/* @hide */
 @VintfStability
 parcelable ReflectingPlane {
   double latitudeDegrees;
   double longitudeDegrees;
   double altitudeMeters;
-  double azimuthDegrees;
+  double reflectingPlaneAzimuthDegrees;
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
index d18c1a7..ebbe684 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss.measurement_corrections;
+/* @hide */
 @VintfStability
 parcelable SingleSatCorrection {
   int singleSatCorrectionFlags;
@@ -39,11 +40,24 @@
   int svid;
   long carrierFrequencyHz;
   float probSatIsLos;
-  float excessPathLengthMeters;
-  float excessPathLengthUncertaintyMeters;
-  android.hardware.gnss.measurement_corrections.ReflectingPlane reflectingPlane;
+  float combinedExcessPathLengthMeters;
+  float combinedExcessPathLengthUncertaintyMeters;
+  float combinedAttenuationDb;
+  android.hardware.gnss.measurement_corrections.SingleSatCorrection.ExcessPathInfo[] excessPathInfos;
   const int SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY = 1;
-  const int SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH = 2;
-  const int SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH_UNC = 4;
-  const int SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE = 8;
+  const int SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH = 2;
+  const int SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC = 4;
+  const int SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION = 16;
+  @VintfStability
+  parcelable ExcessPathInfo {
+    int excessPathInfoFlags;
+    float excessPathLengthMeters;
+    float excessPathLengthUncertaintyMeters;
+    android.hardware.gnss.measurement_corrections.ReflectingPlane reflectingPlane;
+    float attenuationDb;
+    const int EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH = 1;
+    const int EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC = 2;
+    const int EXCESS_PATH_INFO_HAS_REFLECTING_PLANE = 4;
+    const int EXCESS_PATH_INFO_HAS_ATTENUATION = 8;
+  }
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
index f674099..d7a7a96 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss.visibility_control;
+/* @hide */
 @VintfStability
 interface IGnssVisibilityControl {
   void enableNfwLocationAccess(in @utf8InCpp String[] proxyApps);
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl
index 37e1886..c9b96f5 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.gnss.visibility_control;
+/* @hide */
 @VintfStability
 interface IGnssVisibilityControlCallback {
   void nfwNotifyCb(in android.hardware.gnss.visibility_control.IGnssVisibilityControlCallback.NfwNotification notification);
diff --git a/gnss/aidl/android/hardware/gnss/BlocklistedSource.aidl b/gnss/aidl/android/hardware/gnss/BlocklistedSource.aidl
index 8b73092..0c40a49 100644
--- a/gnss/aidl/android/hardware/gnss/BlocklistedSource.aidl
+++ b/gnss/aidl/android/hardware/gnss/BlocklistedSource.aidl
@@ -20,6 +20,8 @@
 
 /**
  * Represents a blocklisted source.
+ *
+ * @hide
  */
 @VintfStability
 parcelable BlocklistedSource {
@@ -33,4 +35,4 @@
      * svid's for the specified constellation.
      */
     int svid;
-}
\ No newline at end of file
+}
diff --git a/gnss/aidl/android/hardware/gnss/CorrelationVector.aidl b/gnss/aidl/android/hardware/gnss/CorrelationVector.aidl
index 6fbabbc..a933c67 100644
--- a/gnss/aidl/android/hardware/gnss/CorrelationVector.aidl
+++ b/gnss/aidl/android/hardware/gnss/CorrelationVector.aidl
@@ -19,6 +19,8 @@
 /**
  * Contains info about the correlation output of incoming GNSS signal and a local copy of
  * its corresponding spreading code at a given frequency offset.
+ *
+ * @hide
  */
 @VintfStability
 parcelable CorrelationVector {
diff --git a/gnss/aidl/android/hardware/gnss/ElapsedRealtime.aidl b/gnss/aidl/android/hardware/gnss/ElapsedRealtime.aidl
index 67d090e..67ecbcb 100644
--- a/gnss/aidl/android/hardware/gnss/ElapsedRealtime.aidl
+++ b/gnss/aidl/android/hardware/gnss/ElapsedRealtime.aidl
@@ -18,6 +18,8 @@
 
 /**
  * Cumulative GNSS power statistics since boot.
+ *
+ * @hide
  */
 @VintfStability
 parcelable ElapsedRealtime {
@@ -50,4 +52,4 @@
      * reported measurements in nanoseconds (68% confidence).
      */
     double timeUncertaintyNs;
-}
\ No newline at end of file
+}
diff --git a/gnss/aidl/android/hardware/gnss/GnssClock.aidl b/gnss/aidl/android/hardware/gnss/GnssClock.aidl
index f416e08..f5c090b 100644
--- a/gnss/aidl/android/hardware/gnss/GnssClock.aidl
+++ b/gnss/aidl/android/hardware/gnss/GnssClock.aidl
@@ -20,6 +20,8 @@
 
 /**
  * Represents an estimate of the GNSS clock time.
+ *
+ * @hide
  */
 @VintfStability
 parcelable GnssClock {
@@ -200,4 +202,4 @@
      * Reference GNSS signal type for inter-signal bias.
      */
     GnssSignalType referenceSignalTypeForIsb;
-}
\ No newline at end of file
+}
diff --git a/gnss/aidl/android/hardware/gnss/GnssConstellationType.aidl b/gnss/aidl/android/hardware/gnss/GnssConstellationType.aidl
index af3e089..2efd1d9 100644
--- a/gnss/aidl/android/hardware/gnss/GnssConstellationType.aidl
+++ b/gnss/aidl/android/hardware/gnss/GnssConstellationType.aidl
@@ -21,6 +21,8 @@
  *
  * This is to specify the navigation satellite system, for example, as listed in Section 3.5 in
  * RINEX Version 3.04.
+ *
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
@@ -40,4 +42,4 @@
     GALILEO = 6,
     /** Indian Regional Navigation Satellite System. */
     IRNSS   = 7,
-}
\ No newline at end of file
+}
diff --git a/gnss/aidl/android/hardware/gnss/GnssData.aidl b/gnss/aidl/android/hardware/gnss/GnssData.aidl
index 6b2068e..075a039 100644
--- a/gnss/aidl/android/hardware/gnss/GnssData.aidl
+++ b/gnss/aidl/android/hardware/gnss/GnssData.aidl
@@ -28,6 +28,8 @@
  *
  * - Reporting of GNSS constellation measurements is mandatory.
  * - Reporting of all tracked constellations are encouraged.
+ *
+ * @hide
  */
 @VintfStability
 parcelable GnssData {
diff --git a/gnss/aidl/android/hardware/gnss/GnssLocation.aidl b/gnss/aidl/android/hardware/gnss/GnssLocation.aidl
index 25aea4d..9946851 100644
--- a/gnss/aidl/android/hardware/gnss/GnssLocation.aidl
+++ b/gnss/aidl/android/hardware/gnss/GnssLocation.aidl
@@ -18,7 +18,7 @@
 
 import android.hardware.gnss.ElapsedRealtime;
 
-/** Represents a location. */
+/** Represents a location. @hide */
 @VintfStability
 parcelable GnssLocation {
     /** Bit mask to indicate GnssLocation has valid latitude and longitude. */
diff --git a/gnss/aidl/android/hardware/gnss/GnssMeasurement.aidl b/gnss/aidl/android/hardware/gnss/GnssMeasurement.aidl
index efecddd..db724a4 100644
--- a/gnss/aidl/android/hardware/gnss/GnssMeasurement.aidl
+++ b/gnss/aidl/android/hardware/gnss/GnssMeasurement.aidl
@@ -28,6 +28,8 @@
  * this struct must be based on GNSS signal measurements only. You must not synthesize measurements
  * by calculating or reporting expected measurements based on known or estimated position, velocity,
  * or time.
+ *
+ * @hide
  */
 @VintfStability
 parcelable GnssMeasurement {
diff --git a/gnss/aidl/android/hardware/gnss/GnssMultipathIndicator.aidl b/gnss/aidl/android/hardware/gnss/GnssMultipathIndicator.aidl
index ec1ce62..98ffe28 100644
--- a/gnss/aidl/android/hardware/gnss/GnssMultipathIndicator.aidl
+++ b/gnss/aidl/android/hardware/gnss/GnssMultipathIndicator.aidl
@@ -19,6 +19,8 @@
 /**
  * Enumeration of available values for the GNSS Measurement's multipath
  * indicator.
+ *
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
@@ -29,4 +31,4 @@
     PRESENT      = 1,
     /** The measurement is indicated to be not affected by multipath. */
     NOT_PRESENT = 2,
-}
\ No newline at end of file
+}
diff --git a/gnss/aidl/android/hardware/gnss/GnssPowerStats.aidl b/gnss/aidl/android/hardware/gnss/GnssPowerStats.aidl
index 2bea44d..3f33dd6 100644
--- a/gnss/aidl/android/hardware/gnss/GnssPowerStats.aidl
+++ b/gnss/aidl/android/hardware/gnss/GnssPowerStats.aidl
@@ -20,6 +20,8 @@
 
 /**
  * Cumulative GNSS power statistics since boot.
+ *
+ * @hide
  */
 @VintfStability
 parcelable GnssPowerStats {
@@ -63,4 +65,4 @@
      * operating in each of the vendor-specific power modes.
      */
     double[] otherModesEnergyMilliJoule;
-}
\ No newline at end of file
+}
diff --git a/gnss/aidl/android/hardware/gnss/GnssSignalType.aidl b/gnss/aidl/android/hardware/gnss/GnssSignalType.aidl
index a16b170..241971f 100644
--- a/gnss/aidl/android/hardware/gnss/GnssSignalType.aidl
+++ b/gnss/aidl/android/hardware/gnss/GnssSignalType.aidl
@@ -20,6 +20,8 @@
 
 /**
  * Represents a GNSS signal type.
+ *
+ * @hide
  */
 @VintfStability
 parcelable GnssSignalType {
diff --git a/gnss/aidl/android/hardware/gnss/IAGnss.aidl b/gnss/aidl/android/hardware/gnss/IAGnss.aidl
index 30b2167..ca67e01 100644
--- a/gnss/aidl/android/hardware/gnss/IAGnss.aidl
+++ b/gnss/aidl/android/hardware/gnss/IAGnss.aidl
@@ -19,7 +19,11 @@
 import android.hardware.gnss.IAGnssCallback;
 import android.hardware.gnss.IAGnssCallback.AGnssType;
 
-/** Extended interface for Assisted GNSS support. */
+/**
+ * Extended interface for Assisted GNSS support.
+ *
+ * @hide
+ */
 @VintfStability
 interface IAGnss {
     /** Access point name IP type */
diff --git a/gnss/aidl/android/hardware/gnss/IAGnssCallback.aidl b/gnss/aidl/android/hardware/gnss/IAGnssCallback.aidl
index 8f881b7..e3a1649 100644
--- a/gnss/aidl/android/hardware/gnss/IAGnssCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/IAGnssCallback.aidl
@@ -16,7 +16,11 @@
 
 package android.hardware.gnss;
 
-/** Callback structure for the AGNSS interface. */
+/**
+ * Callback structure for the AGNSS interface.
+ *
+ * @hide
+ */
 @VintfStability
 interface IAGnssCallback {
     /** AGNSS service type */
diff --git a/gnss/aidl/android/hardware/gnss/IAGnssRil.aidl b/gnss/aidl/android/hardware/gnss/IAGnssRil.aidl
index b505d81..44847f0 100644
--- a/gnss/aidl/android/hardware/gnss/IAGnssRil.aidl
+++ b/gnss/aidl/android/hardware/gnss/IAGnssRil.aidl
@@ -23,6 +23,8 @@
  * Layer interface allows the GNSS chipset to request radio interface layer
  * information from Android platform. Examples of such information are reference
  * location, unique subscriber ID, phone number string and network availability changes.
+ *
+ * @hide
  */
 @VintfStability
 interface IAGnssRil {
diff --git a/gnss/aidl/android/hardware/gnss/IAGnssRilCallback.aidl b/gnss/aidl/android/hardware/gnss/IAGnssRilCallback.aidl
index 485626d..99fe2b7 100644
--- a/gnss/aidl/android/hardware/gnss/IAGnssRilCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/IAGnssRilCallback.aidl
@@ -19,6 +19,8 @@
 /**
  * Callback for IAGnssRil interface. Used to request SET ID and
  * Reference Location.
+ *
+ * @hide
  */
 @VintfStability
 interface IAGnssRilCallback {
diff --git a/gnss/aidl/android/hardware/gnss/IGnss.aidl b/gnss/aidl/android/hardware/gnss/IGnss.aidl
index 12fdbb4..f0b583d 100644
--- a/gnss/aidl/android/hardware/gnss/IGnss.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnss.aidl
@@ -34,6 +34,8 @@
 
 /**
  * Represents the standard GNSS (Global Navigation Satellite System) interface.
+ *
+ * @hide
  */
 @VintfStability
 interface IGnss {
diff --git a/gnss/aidl/android/hardware/gnss/IGnssAntennaInfo.aidl b/gnss/aidl/android/hardware/gnss/IGnssAntennaInfo.aidl
index de83b67..3b173f9 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssAntennaInfo.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssAntennaInfo.aidl
@@ -20,6 +20,8 @@
 
 /**
  * Extended interface for GNSS antenna information support.
+ *
+ * @hide
  */
 @VintfStability
 interface IGnssAntennaInfo {
diff --git a/gnss/aidl/android/hardware/gnss/IGnssAntennaInfoCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssAntennaInfoCallback.aidl
index ef0a7fc..4856551 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssAntennaInfoCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssAntennaInfoCallback.aidl
@@ -18,6 +18,8 @@
 
 /**
  * The callback interface to report GNSS antenna information from the HAL.
+ *
+ * @hide
  */
 @VintfStability
 interface IGnssAntennaInfoCallback {
diff --git a/gnss/aidl/android/hardware/gnss/IGnssBatching.aidl b/gnss/aidl/android/hardware/gnss/IGnssBatching.aidl
index 0d03a0f..2880df6 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssBatching.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssBatching.aidl
@@ -32,6 +32,8 @@
  * As with GNSS Location outputs, source of location must be GNSS satellite measurements, optionally
  * using interial and baro sensors to improve relative motion filtering. No additional absolute
  * positioning information, such as WiFi derived location, may be mixed with the GNSS information.
+ *
+ * @hide
  */
 @VintfStability
 interface IGnssBatching {
diff --git a/gnss/aidl/android/hardware/gnss/IGnssBatchingCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssBatchingCallback.aidl
index b1bfc57..36e8307 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssBatchingCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssBatchingCallback.aidl
@@ -18,7 +18,11 @@
 
 import android.hardware.gnss.GnssLocation;
 
-/** The callback interface to report batched GNSS locations from the HAL. */
+/**
+ * The callback interface to report batched GNSS locations from the HAL.
+ *
+ * @hide
+ */
 @VintfStability
 interface IGnssBatchingCallback {
     /**
diff --git a/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
index 866606f..8633bea 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
@@ -25,6 +25,8 @@
  * This interface is required for the HAL to communicate certain information
  * like status and location info back to the framework, the framework implements
  * the interfaces and passes a handle to the HAL.
+ *
+ * @hide
  */
 @VintfStability
 interface IGnssCallback {
diff --git a/gnss/aidl/android/hardware/gnss/IGnssConfiguration.aidl b/gnss/aidl/android/hardware/gnss/IGnssConfiguration.aidl
index e0ad357..313ae22 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssConfiguration.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssConfiguration.aidl
@@ -20,6 +20,8 @@
 
 /**
  * Extended interface for GNSS Configuration support.
+ *
+ * @hide
  */
 @VintfStability
 interface IGnssConfiguration {
@@ -119,4 +121,4 @@
      * @param blocklist The BlocklistedSource(s) of satellites the HAL must not use.
      */
     void setBlocklist(in BlocklistedSource[] blocklist);
-}
\ No newline at end of file
+}
diff --git a/gnss/aidl/android/hardware/gnss/IGnssDebug.aidl b/gnss/aidl/android/hardware/gnss/IGnssDebug.aidl
index 3071dce5..9e1b5ed 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssDebug.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssDebug.aidl
@@ -24,6 +24,8 @@
  *
  * This information is used for debugging purpose, e.g., shown in a bugreport to
  * describe the chipset states including time, position, and satellite data.
+ *
+ * @hide
  */
 @VintfStability
 interface IGnssDebug {
diff --git a/gnss/aidl/android/hardware/gnss/IGnssGeofence.aidl b/gnss/aidl/android/hardware/gnss/IGnssGeofence.aidl
index bb4ff93..2a540a2 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssGeofence.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssGeofence.aidl
@@ -18,7 +18,11 @@
 
 import android.hardware.gnss.IGnssGeofenceCallback;
 
-/** Extended interface for GNSS Geofence support. */
+/**
+ * Extended interface for GNSS Geofence support.
+ *
+ * @hide
+ */
 @VintfStability
 interface IGnssGeofence {
     /**
diff --git a/gnss/aidl/android/hardware/gnss/IGnssGeofenceCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssGeofenceCallback.aidl
index c176965..5cb8d9c 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssGeofenceCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssGeofenceCallback.aidl
@@ -90,6 +90,8 @@
  * hopefully provide a definitive state transition to the third party
  * application. GNSS Geofence will just be a signal indicating what the GNSS
  * subsystem knows about the Geofence.
+ *
+ * @hide
  */
 @VintfStability
 interface IGnssGeofenceCallback {
diff --git a/gnss/aidl/android/hardware/gnss/IGnssMeasurementCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssMeasurementCallback.aidl
index 328cf2a..a8bd8a3 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssMeasurementCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssMeasurementCallback.aidl
@@ -20,6 +20,8 @@
 
 /**
  * The callback interface to report GNSS Measurement from the HAL.
+ *
+ * @hide
  */
 @VintfStability
 interface IGnssMeasurementCallback {
@@ -29,4 +31,4 @@
      * @param data Contains a reading of GNSS measurements.
      */
     void gnssMeasurementCb(in GnssData data);
-}
\ No newline at end of file
+}
diff --git a/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl b/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
index 102cdcd..8062aed 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
@@ -20,6 +20,8 @@
 
 /**
  * Extended interface for GNSS Measurement support.
+ *
+ * @hide
  */
 @VintfStability
 interface IGnssMeasurementInterface {
diff --git a/gnss/aidl/android/hardware/gnss/IGnssNavigationMessageCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssNavigationMessageCallback.aidl
index 0fdfaf8..6990e19 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssNavigationMessageCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssNavigationMessageCallback.aidl
@@ -16,7 +16,11 @@
 
 package android.hardware.gnss;
 
-/** Represents a GNSS navigation message (or a fragment of it). */
+/**
+ * Represents a GNSS navigation message (or a fragment of it).
+ *
+ * @hide
+ */
 @VintfStability
 interface IGnssNavigationMessageCallback {
     /**
diff --git a/gnss/aidl/android/hardware/gnss/IGnssNavigationMessageInterface.aidl b/gnss/aidl/android/hardware/gnss/IGnssNavigationMessageInterface.aidl
index e2f57c3..6c0f83a 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssNavigationMessageInterface.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssNavigationMessageInterface.aidl
@@ -20,6 +20,8 @@
 
 /**
  * Extended interface for GNSS navigation message reporting support.
+ *
+ * @hide
  */
 @VintfStability
 interface IGnssNavigationMessageInterface {
diff --git a/gnss/aidl/android/hardware/gnss/IGnssPowerIndication.aidl b/gnss/aidl/android/hardware/gnss/IGnssPowerIndication.aidl
index 93fdadc..1486095 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssPowerIndication.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssPowerIndication.aidl
@@ -20,6 +20,8 @@
 
 /**
  * Extended interface for GNSS Power Indication support.
+ *
+ * @hide
  */
 @VintfStability
 interface IGnssPowerIndication {
@@ -36,4 +38,4 @@
      * from IGnssPowerIndicationCallback.gnssPowerStatsCb().
      */
     oneway void requestGnssPowerStats();
-}
\ No newline at end of file
+}
diff --git a/gnss/aidl/android/hardware/gnss/IGnssPowerIndicationCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssPowerIndicationCallback.aidl
index 4474c0c..8e6a6e4 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssPowerIndicationCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssPowerIndicationCallback.aidl
@@ -20,6 +20,8 @@
 
 /**
  * The callback interface to report GNSS Power Indication from the HAL.
+ *
+ * @hide
  */
 @VintfStability
 interface IGnssPowerIndicationCallback {
@@ -60,4 +62,4 @@
      * @param gnssPowerStats GNSS power statistics since boot.
      */
     oneway void gnssPowerStatsCb(in GnssPowerStats gnssPowerStats);
-}
\ No newline at end of file
+}
diff --git a/gnss/aidl/android/hardware/gnss/IGnssPsds.aidl b/gnss/aidl/android/hardware/gnss/IGnssPsds.aidl
index 7c46096..8de2dcf 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssPsds.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssPsds.aidl
@@ -22,6 +22,8 @@
 /**
  * This interface is used by the GNSS HAL to request the framework to download Predicted Satellite
  * Data Service data.
+ *
+ * @hide
  */
 @VintfStability
 interface IGnssPsds {
@@ -42,4 +44,4 @@
      * @param callback Handle to the IGnssPsdsCallback interface.
      */
     void setCallback(in IGnssPsdsCallback callback);
-}
\ No newline at end of file
+}
diff --git a/gnss/aidl/android/hardware/gnss/IGnssPsdsCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssPsdsCallback.aidl
index 72b693b..bc31000 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssPsdsCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssPsdsCallback.aidl
@@ -21,6 +21,8 @@
 /**
  * This interface is used by the GNSS HAL to request download data from Predicted Satellite Data
  * Service (PSDS).
+ *
+ * @hide
  */
 @VintfStability
 interface IGnssPsdsCallback {
@@ -34,4 +36,4 @@
      * @param psdsType Type of PSDS data.
      */
     void downloadRequestCb(in PsdsType psdsType);
-}
\ No newline at end of file
+}
diff --git a/gnss/aidl/android/hardware/gnss/PsdsType.aidl b/gnss/aidl/android/hardware/gnss/PsdsType.aidl
index d4fec77..67a74c7 100644
--- a/gnss/aidl/android/hardware/gnss/PsdsType.aidl
+++ b/gnss/aidl/android/hardware/gnss/PsdsType.aidl
@@ -16,7 +16,11 @@
 
 package android.hardware.gnss;
 
-/** The type of PSDS data. */
+/**
+ * The type of PSDS data.
+ *
+ * @hide
+ */
 @VintfStability
 @Backing(type="int")
 enum PsdsType {
diff --git a/gnss/aidl/android/hardware/gnss/SatelliteClockInfo.aidl b/gnss/aidl/android/hardware/gnss/SatelliteClockInfo.aidl
index 4b7d5d6..84f35ff 100644
--- a/gnss/aidl/android/hardware/gnss/SatelliteClockInfo.aidl
+++ b/gnss/aidl/android/hardware/gnss/SatelliteClockInfo.aidl
@@ -18,6 +18,8 @@
 
 /**
  * Contains estimates of the satellite clock info.
+ *
+ * @hide
  */
 @VintfStability
 parcelable SatelliteClockInfo {
diff --git a/gnss/aidl/android/hardware/gnss/SatellitePositionEcef.aidl b/gnss/aidl/android/hardware/gnss/SatellitePositionEcef.aidl
index febe623..105cb85 100644
--- a/gnss/aidl/android/hardware/gnss/SatellitePositionEcef.aidl
+++ b/gnss/aidl/android/hardware/gnss/SatellitePositionEcef.aidl
@@ -21,6 +21,8 @@
  *
  * The satellite position must be defined at the time of transmission of the
  * signal receivedSvTimeNs.
+ *
+ * @hide
  */
 @VintfStability
 parcelable SatellitePositionEcef {
diff --git a/gnss/aidl/android/hardware/gnss/SatellitePvt.aidl b/gnss/aidl/android/hardware/gnss/SatellitePvt.aidl
index e79249d..2d52415 100644
--- a/gnss/aidl/android/hardware/gnss/SatellitePvt.aidl
+++ b/gnss/aidl/android/hardware/gnss/SatellitePvt.aidl
@@ -23,6 +23,8 @@
 /**
  * Contains estimates of the satellite position, velocity and time in the
  * ECEF coordinate frame.
+ *
+ * @hide
  */
 @VintfStability
 parcelable SatellitePvt {
@@ -76,12 +78,13 @@
     double tropoDelayMeters;
 
     /**
-     * Time of Clock.
+     * Time of Clock in seconds.
      *
-     * This is defined in GPS ICD200 documentation
-     * (e.g., https://www.gps.gov/technical/icwg/IS-GPS-200H.pdf).
+     * This value is defined in seconds since GPS epoch, regardless of the constellation.
+     *
+     * The value must not be encoded as in GPS ICD200 documentation.
      */
-    int TOC;
+    long timeOfClockSeconds;
 
     /**
      * Issue of Data, Clock.
@@ -91,15 +94,16 @@
      *
      * The field must be set to 0 if it is not supported.
      */
-    int IODC;
+    int issueOfDataClock;
 
     /**
-     * Time of Ephemeris.
+     * Time of Ephemeris in seconds.
      *
-     * This is defined in GPS ICD200 documentation
-     * (e.g., https://www.gps.gov/technical/icwg/IS-GPS-200H.pdf).
+     * This value is defined in seconds since GPS epoch, regardless of the constellation.
+     *
+     * The value must not be encoded as in GPS ICD200 documentation.
      */
-    int TOE;
+    long timeOfEphemerisSeconds;
 
     /**
      * Issue of Data, Ephemeris.
@@ -109,7 +113,7 @@
      *
      * The field must be set to 0 if it is not supported.
      */
-    int IODE;
+    int issueOfDataEphemeris;
 
     /** Satellite's ephemeris source */
     @VintfStability
diff --git a/gnss/aidl/android/hardware/gnss/SatelliteVelocityEcef.aidl b/gnss/aidl/android/hardware/gnss/SatelliteVelocityEcef.aidl
index f2d7ab6..3d3ea1a 100644
--- a/gnss/aidl/android/hardware/gnss/SatelliteVelocityEcef.aidl
+++ b/gnss/aidl/android/hardware/gnss/SatelliteVelocityEcef.aidl
@@ -21,6 +21,8 @@
  *
  * The satellite velocity must be defined at the time of transmission of the
  * signal receivedSvTimeNs.
+ *
+ * @hide
  */
 @VintfStability
 parcelable SatelliteVelocityEcef {
diff --git a/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl b/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
index d695e70..4732ffc 100644
--- a/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsCallback.aidl
@@ -18,6 +18,8 @@
 
 /**
  * GNSS measurement corrections callback interface.
+ *
+ * @hide
  */
 @VintfStability
 interface IMeasurementCorrectionsCallback {
diff --git a/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl b/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl
index eeabc6d..841fed3 100644
--- a/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl
+++ b/gnss/aidl/android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.aidl
@@ -21,6 +21,8 @@
 
 /**
  * Interface for measurement corrections support.
+ *
+ * @hide
  */
 @VintfStability
 interface IMeasurementCorrectionsInterface {
diff --git a/gnss/aidl/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl b/gnss/aidl/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl
index 285c7d4..d6224b4 100644
--- a/gnss/aidl/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl
+++ b/gnss/aidl/android/hardware/gnss/measurement_corrections/MeasurementCorrections.aidl
@@ -22,6 +22,8 @@
  * A struct containing a set of measurement corrections for all used GNSS satellites at the location
  * specified by latitudeDegrees, longitudeDegrees, altitudeMeters and at the time of week specified
  * toaGpsNanosecondsOfWeek
+ *
+ * @hide
  */
 @VintfStability
 parcelable MeasurementCorrections {
diff --git a/gnss/aidl/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl b/gnss/aidl/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
index 9bf2b44..8104372 100644
--- a/gnss/aidl/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
+++ b/gnss/aidl/android/hardware/gnss/measurement_corrections/ReflectingPlane.aidl
@@ -23,6 +23,8 @@
  * The value is only valid if HAS_REFLECTING_PLANE flag is set. An invalid reflecting plane
  * means either reflection planes serving is not supported or the satellite signal has gone
  * through multiple reflections.
+ *
+ * @hide
  */
 @VintfStability
 parcelable ReflectingPlane {
@@ -39,5 +41,5 @@
     double altitudeMeters;
 
     /** Represents azimuth clockwise from north of the reflecting plane in degrees. */
-    double azimuthDegrees;
+    double reflectingPlaneAzimuthDegrees;
 }
diff --git a/gnss/aidl/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl b/gnss/aidl/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
index d9f7105..56c691c 100644
--- a/gnss/aidl/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
+++ b/gnss/aidl/android/hardware/gnss/measurement_corrections/SingleSatCorrection.aidl
@@ -23,18 +23,20 @@
  * A struct with measurement corrections for a single visible satellites
  *
  * The bit mask singleSatCorrectionFlags indicates which correction values are valid in the struct
+ *
+ * @hide
  */
 @VintfStability
 parcelable SingleSatCorrection {
     /** Bit mask to indicate which values are valid in a SingleSatCorrection object. */
-    /** GnssSingleSatCorrectionFlags has valid satellite-is-line-of-sight-probability field. */
+    /** GnssSingleSatCorrectionFlags has valid probSatIsLos field. */
     const int SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY = 0x0001;
-    /** GnssSingleSatCorrectionFlags has valid Excess Path Length field. */
-    const int SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH = 0x0002;
-    /** GnssSingleSatCorrectionFlags has valid Excess Path Length Uncertainty field. */
-    const int SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH_UNC = 0x0004;
-    /** GnssSingleSatCorrectionFlags has valid Reflecting Plane field. */
-    const int SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE = 0x0008;
+    /** GnssSingleSatCorrectionFlags has valid combinedExcessPathLengthMeters field. */
+    const int SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH = 0x0002;
+    /** GnssSingleSatCorrectionFlags has valid combinedExcessPathLengthUncertaintyMeters field. */
+    const int SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC = 0x0004;
+    /** GnssSingleSatCorrectionFlags has valid combinedAttenuationDb field. */
+    const int SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION = 0x0010;
 
     /** Contains GnssSingleSatCorrectionFlags bits. */
     int singleSatCorrectionFlags;
@@ -65,21 +67,74 @@
     float probSatIsLos;
 
     /**
-     * Excess path length to be subtracted from pseudorange before using it in calculating location.
+     * Combined excess path length to be subtracted from pseudorange before using it in
+     * calculating location.
      *
-     * Note this value is NOT to be used to adjust the GnsseasurementCallback outputs.
+     * The value is computed by correlating the individual paths and picking the delay at the
+     * highest peak.
+     *
+     * Note this value is NOT to be used to adjust the GnssMeasurementCallback outputs.
      */
-    float excessPathLengthMeters;
-
-    /** Error estimate (1-sigma) for the Excess path length estimate */
-    float excessPathLengthUncertaintyMeters;
+    float combinedExcessPathLengthMeters;
 
     /**
-     * Defines the reflecting plane characteristics such as location and azimuth
+     * Error estimate (1-sigma) for the Excess path length estimate.
      *
-     * The value is only valid if HAS_REFLECTING_PLANE flag is set. An invalid reflecting plane
-     * means either reflection planes serving is not supported or the satellite signal has gone
-     * through multiple reflections.
+     * The value is computed by combining the individual excessPathLengthUncertaintyMeters values
+     * into a single value for this satellite.
      */
-    ReflectingPlane reflectingPlane;
+    float combinedExcessPathLengthUncertaintyMeters;
+
+    /**
+     * Combined expected reduction of signal strength for this satellite in non-negative dB.
+     */
+    float combinedAttenuationDb;
+
+    /**
+     * A struct for the info of an excess path caused by reflection.
+     */
+    @VintfStability
+    parcelable ExcessPathInfo {
+        /** ExcessPathInfo has valid Excess Path Length field. */
+        const int EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH = 0x0001;
+        /** ExcessPathInfo has valid Excess Path Length Uncertainty field. */
+        const int EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC = 0x0002;
+        /** ExcessPathInfo has valid Reflecting Plane field. */
+        const int EXCESS_PATH_INFO_HAS_REFLECTING_PLANE = 0x0004;
+        /** ExcessPathInfo has valid Attenuation field. */
+        const int EXCESS_PATH_INFO_HAS_ATTENUATION = 0x0008;
+
+        /** Contains flag bits to indicate which fields exist in the ExcessPathInfo object. */
+        int excessPathInfoFlags;
+
+        /**
+         * Excess path length to be subtracted from pseudorange before using it in calculating
+         * location.
+         *
+         * Note this value is NOT to be used to adjust the GnssMeasurementCallback outputs.
+         */
+        float excessPathLengthMeters;
+
+        /** Error estimate (1-sigma) for the Excess path length estimate. */
+        float excessPathLengthUncertaintyMeters;
+
+        /**
+         * Defines the reflecting plane characteristics such as location and azimuth.
+         *
+         * The value is only valid if HAS_REFLECTING_PLANE flag is set. An invalid reflecting plane
+         * means either reflection planes serving is not supported or the satellite signal has gone
+         * through multiple reflections.
+         */
+        ReflectingPlane reflectingPlane;
+
+        /**
+         * The expected reduction of signal strength of this path in non-negative dB.
+         */
+        float attenuationDb;
+    }
+
+    /**
+     * A list of excess path info.
+     */
+    ExcessPathInfo[] excessPathInfos;
 }
diff --git a/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl b/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
index c9c1549..2fdf0be 100644
--- a/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
+++ b/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControl.aidl
@@ -47,6 +47,8 @@
  * status, or other information that can be used to derive user location to any entity when not
  * expressly authorized by this HAL. This includes all endpoints for location information
  * off the device, including carriers, vendors, OEM and others directly or indirectly.
+ *
+ * @hide
  */
 @VintfStability
 interface IGnssVisibilityControl {
diff --git a/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl b/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl
index 051fbe6..8b08098 100644
--- a/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/visibility_control/IGnssVisibilityControlCallback.aidl
@@ -18,6 +18,8 @@
 
 /**
  * GNSS location reporting permissions and notification callback interface.
+ *
+ * @hide
  */
 @VintfStability
 interface IGnssVisibilityControlCallback {
diff --git a/gnss/aidl/default/Android.bp b/gnss/aidl/default/Android.bp
index 4543665..c8ae6b2 100644
--- a/gnss/aidl/default/Android.bp
+++ b/gnss/aidl/default/Android.bp
@@ -31,7 +31,6 @@
     ],
     vintf_fragments: [
         "gnss-default.xml",
-        "gnss@2.1-service.xml",
     ],
     vendor: true,
     cflags: [
@@ -47,7 +46,6 @@
         "liblog",
         "android.hardware.gnss@2.1",
         "android.hardware.gnss@2.0",
-        "android.hardware.gnss@1.1",
         "android.hardware.gnss@1.0",
         "android.hardware.gnss.measurement_corrections@1.1",
         "android.hardware.gnss.measurement_corrections@1.0",
@@ -62,7 +60,6 @@
         "GnssBatching.cpp",
         "GnssDebug.cpp",
         "GnssGeofence.cpp",
-        "GnssHidlHal.cpp",
         "GnssNavigationMessageInterface.cpp",
         "GnssPowerIndication.cpp",
         "GnssPsds.cpp",
diff --git a/gnss/aidl/default/GnssHidlHal.cpp b/gnss/aidl/default/GnssHidlHal.cpp
deleted file mode 100644
index 10b0106..0000000
--- a/gnss/aidl/default/GnssHidlHal.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "GnssHidlHal"
-
-#include "GnssHidlHal.h"
-
-namespace aidl::android::hardware::gnss {
-
-using GnssSvInfo = ::android::hardware::gnss::V2_1::IGnssCallback::GnssSvInfo;
-
-GnssHidlHal::GnssHidlHal(const std::shared_ptr<Gnss>& gnssAidl) : mGnssAidl(gnssAidl) {
-    Gnss* iGnss = mGnssAidl.get();
-    std::shared_ptr<IGnssConfiguration> iGnssConfiguration;
-    auto status = iGnss->getExtensionGnssConfiguration(&iGnssConfiguration);
-    if (!status.isOk()) {
-        ALOGE("Failed to getExtensionGnssConfiguration.");
-    } else {
-        mGnssConfigurationAidl = iGnss->mGnssConfiguration;
-    }
-
-    std::shared_ptr<IGnssPowerIndication> iGnssPowerIndication;
-    status = iGnss->getExtensionGnssPowerIndication(&iGnssPowerIndication);
-    if (!status.isOk()) {
-        ALOGE("Failed to getExtensionGnssPowerIndication.");
-    } else {
-        mGnssPowerIndicationAidl = iGnss->mGnssPowerIndication;
-    }
-};
-
-hidl_vec<GnssSvInfo> GnssHidlHal::filterBlocklistedSatellitesV2_1(
-        hidl_vec<GnssSvInfo> gnssSvInfoList) {
-    if (mGnssConfigurationAidl == nullptr) {
-        ALOGE("Handle to AIDL GnssConfiguration is not available.");
-        return gnssSvInfoList;
-    }
-    for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
-        if (mGnssConfigurationAidl->isBlocklistedV2_1(gnssSvInfoList[i])) {
-            ALOGD("Blocklisted constellation: %d, svid: %d",
-                  (int)gnssSvInfoList[i].v2_0.constellation, gnssSvInfoList[i].v2_0.v1_0.svid);
-            gnssSvInfoList[i].v2_0.v1_0.svFlag &= ~static_cast<uint8_t>(
-                    ::android::hardware::gnss::V1_0::IGnssCallback::GnssSvFlags::USED_IN_FIX);
-        }
-    }
-    return gnssSvInfoList;
-}
-
-void GnssHidlHal::notePowerConsumption() {
-    mGnssPowerIndicationAidl->notePowerConsumption();
-}
-
-}  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssHidlHal.h b/gnss/aidl/default/GnssHidlHal.h
deleted file mode 100644
index 5fb4f97..0000000
--- a/gnss/aidl/default/GnssHidlHal.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "Gnss.h"
-#include "GnssConfiguration.h"
-#include "v2_1/GnssTemplate.h"
-
-namespace aidl::android::hardware::gnss {
-
-class GnssHidlHal : public ::android::hardware::gnss::common::implementation::GnssTemplate<
-                            ::android::hardware::gnss::V2_1::IGnss> {
-  public:
-    GnssHidlHal(const std::shared_ptr<Gnss>& gnssAidl);
-
-  private:
-    hidl_vec<::android::hardware::gnss::V2_1::IGnssCallback::GnssSvInfo>
-    filterBlocklistedSatellitesV2_1(
-            hidl_vec<::android::hardware::gnss::V2_1::IGnssCallback::GnssSvInfo> gnssSvInfoList)
-            override;
-    void notePowerConsumption() override;
-
-    std::shared_ptr<Gnss> mGnssAidl;
-    std::shared_ptr<GnssConfiguration> mGnssConfigurationAidl;
-    std::shared_ptr<GnssPowerIndication> mGnssPowerIndicationAidl;
-};
-
-}  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/MeasurementCorrectionsInterface.cpp b/gnss/aidl/default/MeasurementCorrectionsInterface.cpp
index 0f1851c..66270c8 100644
--- a/gnss/aidl/default/MeasurementCorrectionsInterface.cpp
+++ b/gnss/aidl/default/MeasurementCorrectionsInterface.cpp
@@ -37,16 +37,26 @@
           static_cast<int>(corrections.satCorrections.size()));
     for (auto singleSatCorrection : corrections.satCorrections) {
         ALOGD("singleSatCorrection = flags: %d, constellation: %d, svid: %d"
-              ", cfHz: %" PRId64 ", probLos: %f, epl: %f, eplUnc: %f",
+              ", cfHz: %" PRId64
+              ", probLos: %f, combinedEpl: %f, combinedEplUnc: %f, combinedAttenuation: %f"
+              ", excessPathInfos.size: %d",
               singleSatCorrection.singleSatCorrectionFlags, singleSatCorrection.constellation,
               singleSatCorrection.svid, singleSatCorrection.carrierFrequencyHz,
-              singleSatCorrection.probSatIsLos, singleSatCorrection.excessPathLengthMeters,
-              singleSatCorrection.excessPathLengthUncertaintyMeters);
-        ALOGD("reflecting plane = lat: %f, lng: %f, alt: %f, azm: %f",
-              singleSatCorrection.reflectingPlane.latitudeDegrees,
-              singleSatCorrection.reflectingPlane.longitudeDegrees,
-              singleSatCorrection.reflectingPlane.altitudeMeters,
-              singleSatCorrection.reflectingPlane.azimuthDegrees);
+              singleSatCorrection.probSatIsLos, singleSatCorrection.combinedExcessPathLengthMeters,
+              singleSatCorrection.combinedExcessPathLengthUncertaintyMeters,
+              singleSatCorrection.combinedAttenuationDb,
+              static_cast<int>(singleSatCorrection.excessPathInfos.size()));
+
+        for (auto excessPathInfo : singleSatCorrection.excessPathInfos) {
+            ALOGD("excessPathInfo = epl: %f, eplUnc: %f, attenuation: %f",
+                  excessPathInfo.excessPathLengthMeters,
+                  excessPathInfo.excessPathLengthUncertaintyMeters, excessPathInfo.attenuationDb);
+            ALOGD("reflecting plane = lat: %f, lng: %f, alt: %f, azm: %f",
+                  excessPathInfo.reflectingPlane.latitudeDegrees,
+                  excessPathInfo.reflectingPlane.longitudeDegrees,
+                  excessPathInfo.reflectingPlane.altitudeMeters,
+                  excessPathInfo.reflectingPlane.reflectingPlaneAzimuthDegrees);
+        }
     }
     return ndk::ScopedAStatus::ok();
 }
diff --git a/gnss/aidl/default/gnss@2.1-service.xml b/gnss/aidl/default/gnss@2.1-service.xml
deleted file mode 100644
index 12a1fdf..0000000
--- a/gnss/aidl/default/gnss@2.1-service.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<manifest version="1.0" type="device">
-    <hal format="hidl">
-        <name>android.hardware.gnss</name>
-        <transport>hwbinder</transport>
-        <version>2.1</version>
-        <version>1.1</version>
-        <interface>
-            <name>IGnss</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-</manifest>
diff --git a/gnss/aidl/default/service.cpp b/gnss/aidl/default/service.cpp
index bbe34f1..162532b 100644
--- a/gnss/aidl/default/service.cpp
+++ b/gnss/aidl/default/service.cpp
@@ -24,15 +24,12 @@
 #include <log/log.h>
 #include <pthread.h>
 #include "Gnss.h"
-#include "GnssHidlHal.h"
 
 using aidl::android::hardware::gnss::Gnss;
-using aidl::android::hardware::gnss::GnssHidlHal;
 using ::android::OK;
 using ::android::sp;
 using ::android::hardware::configureRpcThreadpool;
 using ::android::hardware::joinRpcThreadpool;
-using ::android::hardware::gnss::V2_1::IGnss;
 
 int main() {
     ABinderProcess_setThreadPoolMaxThreadCount(1);
@@ -44,14 +41,6 @@
             AServiceManager_addService(gnssAidl->asBinder().get(), instance.c_str());
     CHECK_EQ(status, STATUS_OK);
 
-    sp<IGnss> gnss = new GnssHidlHal(gnssAidl);
-    configureRpcThreadpool(1, true /* will join */);
-    if (gnss->registerAsService() != OK) {
-        ALOGE("Could not register gnss 2.1 service.");
-        return 0;
-    }
-
-    joinRpcThreadpool();
     ABinderProcess_joinThreadPool();
 
     return EXIT_FAILURE;  // should not reach
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
index 365f9d3..54946fb 100644
--- a/gnss/aidl/vts/gnss_hal_test_cases.cpp
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -366,12 +366,13 @@
         ASSERT_TRUE(satellitePvt.tropoDelayMeters > 0 && satellitePvt.tropoDelayMeters < 100);
     }
     if (interfaceVersion >= 2) {
-        ASSERT_TRUE(satellitePvt.TOC >= 0 && satellitePvt.TOC <= 604784);
-        ASSERT_TRUE(satellitePvt.TOE >= 0 && satellitePvt.TOE <= 604784);
+        ASSERT_TRUE(satellitePvt.timeOfClockSeconds >= 0);
+        ASSERT_TRUE(satellitePvt.timeOfEphemerisSeconds >= 0);
         // IODC has 10 bits
-        ASSERT_TRUE(satellitePvt.IODC >= 0 && satellitePvt.IODC <= 1023);
+        ASSERT_TRUE(satellitePvt.issueOfDataClock >= 0 && satellitePvt.issueOfDataClock <= 1023);
         // IODE has 8 bits
-        ASSERT_TRUE(satellitePvt.IODE >= 0 && satellitePvt.IODE <= 255);
+        ASSERT_TRUE(satellitePvt.issueOfDataEphemeris >= 0 &&
+                    satellitePvt.issueOfDataEphemeris <= 255);
     }
 }
 
diff --git a/gnss/common/utils/default/GnssReplayUtils.cpp b/gnss/common/utils/default/GnssReplayUtils.cpp
index 37da571..6caf313 100644
--- a/gnss/common/utils/default/GnssReplayUtils.cpp
+++ b/gnss/common/utils/default/GnssReplayUtils.cpp
@@ -16,24 +16,42 @@
 
 #include "GnssReplayUtils.h"
 
+#include <array>
+
 namespace android {
 namespace hardware {
 namespace gnss {
 namespace common {
 
 std::string ReplayUtils::getGnssPath() {
-    char devname_value[PROPERTY_VALUE_MAX] = "";
-    if (property_get("debug.location.gnss.devname", devname_value, NULL) > 0) {
-        return devname_value;
+    std::array<char, PROPERTY_VALUE_MAX> devname_value;
+
+    devname_value.fill(0);
+    if (property_get("debug.location.gnss.devname", devname_value.begin(), NULL) > 0) {
+        return devname_value.begin();
     }
+
+    devname_value.fill(0);
+    if (property_get("vendor.ser.gnss-uart", devname_value.begin(), NULL) > 0) {
+        return devname_value.begin();
+    }
+
     return GNSS_PATH;
 }
 
 std::string ReplayUtils::getFixedLocationPath() {
-    char devname_value[PROPERTY_VALUE_MAX] = "";
-    if (property_get("debug.location.fixedlocation.devname", devname_value, NULL) > 0) {
-        return devname_value;
+    std::array<char, PROPERTY_VALUE_MAX> devname_value;
+
+    devname_value.fill(0);
+    if (property_get("debug.location.fixedlocation.devname", devname_value.begin(), NULL) > 0) {
+        return devname_value.begin();
     }
+
+    devname_value.fill(0);
+    if (property_get("vendor.ser.gnss-uart", devname_value.begin(), NULL) > 0) {
+        return devname_value.begin();
+    }
+
     return FIXED_LOCATION_PATH;
 }
 
diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp
index a519d3a..4de49f3 100644
--- a/gnss/common/utils/default/Utils.cpp
+++ b/gnss/common/utils/default/Utils.cpp
@@ -201,10 +201,10 @@
                             .tropoDelayMeters = 3.882265204404031,
                             .ephemerisSource =
                                     SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
-                            .TOC = 12345,
-                            .IODC = 143,
-                            .TOE = 9876,
-                            .IODE = 48,
+                            .timeOfClockSeconds = 12345,
+                            .issueOfDataClock = 143,
+                            .timeOfEphemerisSeconds = 9876,
+                            .issueOfDataEphemeris = 48,
                     },
             .correlationVectors = {}};
 
diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp
index 4c725a8..69e2b34 100644
--- a/gnss/common/utils/vts/Utils.cpp
+++ b/gnss/common/utils/vts/Utils.cpp
@@ -38,6 +38,7 @@
 using ReflectingPlaneAidl = android::hardware::gnss::measurement_corrections::ReflectingPlane;
 using SingleSatCorrectionAidl =
         android::hardware::gnss::measurement_corrections::SingleSatCorrection;
+using ExcessPathInfo = SingleSatCorrectionAidl::ExcessPathInfo;
 
 template <>
 int64_t Utils::getLocationTimestampMillis(const android::hardware::gnss::GnssLocation& location) {
@@ -170,38 +171,68 @@
     return mockCorrections_1_1;
 }
 
+namespace {
+const ExcessPathInfo createExcessPathInfo(float excessPathLengthMeters,
+                                          float excessPathLengthUncertaintyMeters,
+                                          const ReflectingPlaneAidl* reflectingPlane,
+                                          float attenuationDb) {
+    ExcessPathInfo excessPathInfo;
+    excessPathInfo.excessPathInfoFlags =
+            ExcessPathInfo::EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH |
+            ExcessPathInfo::EXCESS_PATH_INFO_HAS_EXCESS_PATH_LENGTH_UNC |
+            ExcessPathInfo::EXCESS_PATH_INFO_HAS_ATTENUATION |
+            (reflectingPlane == nullptr ? 0
+                                        : ExcessPathInfo::EXCESS_PATH_INFO_HAS_REFLECTING_PLANE);
+    excessPathInfo.excessPathLengthMeters = excessPathLengthMeters;
+    excessPathInfo.excessPathLengthUncertaintyMeters = excessPathLengthUncertaintyMeters;
+    if (reflectingPlane != nullptr) {
+        excessPathInfo.reflectingPlane = *reflectingPlane;
+    }
+    excessPathInfo.attenuationDb = attenuationDb;
+    return excessPathInfo;
+}
+}  // anonymous namespace
+
 const MeasurementCorrectionsAidl Utils::getMockMeasurementCorrections_aidl() {
     ReflectingPlaneAidl reflectingPlane;
     reflectingPlane.latitudeDegrees = 37.4220039;
     reflectingPlane.longitudeDegrees = -122.0840991;
     reflectingPlane.altitudeMeters = 250.35;
-    reflectingPlane.azimuthDegrees = 203.0;
+    reflectingPlane.reflectingPlaneAzimuthDegrees = 203.0;
 
     SingleSatCorrectionAidl singleSatCorrection1;
     singleSatCorrection1.singleSatCorrectionFlags =
             SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY |
-            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH |
-            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH_UNC |
-            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_REFLECTING_PLANE;
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH |
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC |
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION;
     singleSatCorrection1.constellation = android::hardware::gnss::GnssConstellationType::GPS;
     singleSatCorrection1.svid = 12;
     singleSatCorrection1.carrierFrequencyHz = 1.59975e+09;
     singleSatCorrection1.probSatIsLos = 0.50001;
-    singleSatCorrection1.excessPathLengthMeters = 137.4802;
-    singleSatCorrection1.excessPathLengthUncertaintyMeters = 25.5;
-    singleSatCorrection1.reflectingPlane = reflectingPlane;
+    singleSatCorrection1.combinedExcessPathLengthMeters = 203.5;
+    singleSatCorrection1.combinedExcessPathLengthUncertaintyMeters = 59.1;
+    singleSatCorrection1.combinedAttenuationDb = -4.3;
+    singleSatCorrection1.excessPathInfos.push_back(
+            createExcessPathInfo(137.4, 25.5, &reflectingPlane, -3.5));
+    singleSatCorrection1.excessPathInfos.push_back(
+            createExcessPathInfo(296.3, 87.2, &reflectingPlane, -5.1));
 
     SingleSatCorrectionAidl singleSatCorrection2;
     singleSatCorrection2.singleSatCorrectionFlags =
             SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_SAT_IS_LOS_PROBABILITY |
-            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH |
-            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_EXCESS_PATH_LENGTH_UNC;
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH |
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_COMBINED_EXCESS_PATH_LENGTH_UNC |
+            SingleSatCorrectionAidl::SINGLE_SAT_CORRECTION_HAS_COMBINED_ATTENUATION;
     singleSatCorrection2.constellation = GnssConstellationType::GPS;
     singleSatCorrection2.svid = 9;
     singleSatCorrection2.carrierFrequencyHz = 1.59975e+09;
     singleSatCorrection2.probSatIsLos = 0.873;
-    singleSatCorrection2.excessPathLengthMeters = 26.294;
-    singleSatCorrection2.excessPathLengthUncertaintyMeters = 10.0;
+    singleSatCorrection2.combinedExcessPathLengthMeters = 26.294;
+    singleSatCorrection2.combinedExcessPathLengthUncertaintyMeters = 10.0;
+    singleSatCorrection2.combinedAttenuationDb = -0.5;
+    singleSatCorrection2.excessPathInfos.push_back(
+            createExcessPathInfo(26.294, 10.0, nullptr, -0.5));
 
     std::vector<SingleSatCorrectionAidl> singleSatCorrections = {singleSatCorrection1,
                                                                  singleSatCorrection2};
diff --git a/graphics/bufferqueue/1.0/Android.bp b/graphics/bufferqueue/1.0/Android.bp
index c3d38d0..11559b2 100644
--- a/graphics/bufferqueue/1.0/Android.bp
+++ b/graphics/bufferqueue/1.0/Android.bp
@@ -27,6 +27,7 @@
     gen_java: true,
     apex_available: [
         "//apex_available:platform",
+        "com.android.bluetooth",
         "com.android.media",
         "com.android.media.swcodec",
     ],
diff --git a/graphics/bufferqueue/2.0/Android.bp b/graphics/bufferqueue/2.0/Android.bp
index 33d9104..552daff 100644
--- a/graphics/bufferqueue/2.0/Android.bp
+++ b/graphics/bufferqueue/2.0/Android.bp
@@ -29,6 +29,7 @@
     gen_java: true,
     apex_available: [
         "//apex_available:platform",
+        "com.android.bluetooth",
         "com.android.media",
         "com.android.media.swcodec",
     ],
diff --git a/graphics/common/1.0/Android.bp b/graphics/common/1.0/Android.bp
index ac158d9..19c51cd 100644
--- a/graphics/common/1.0/Android.bp
+++ b/graphics/common/1.0/Android.bp
@@ -23,6 +23,7 @@
     gen_java_constants: true,
     apex_available: [
         "//apex_available:platform",
+        "com.android.bluetooth",
         "com.android.media.swcodec",
         "test_com.android.media.swcodec",
     ],
diff --git a/graphics/common/1.1/Android.bp b/graphics/common/1.1/Android.bp
index e45d6dd..0f1b5bf 100644
--- a/graphics/common/1.1/Android.bp
+++ b/graphics/common/1.1/Android.bp
@@ -26,6 +26,7 @@
     gen_java_constants: true,
     apex_available: [
         "//apex_available:platform",
+        "com.android.bluetooth",
         "com.android.media.swcodec",
         "test_com.android.media.swcodec",
     ],
diff --git a/graphics/common/1.2/Android.bp b/graphics/common/1.2/Android.bp
index c23085d..ce3350d 100644
--- a/graphics/common/1.2/Android.bp
+++ b/graphics/common/1.2/Android.bp
@@ -27,6 +27,7 @@
     gen_java_constants: true,
     apex_available: [
         "//apex_available:platform",
+        "com.android.bluetooth",
         "com.android.media.swcodec",
         "test_com.android.media.swcodec",
     ],
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index eb67d34..9ffd7d5 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -26,6 +26,7 @@
 cc_test {
     name: "VtsHalGraphicsComposerV2_1TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: ["VtsHalGraphicsComposerV2_1TargetTest.cpp"],
     srcs: ["VtsHalGraphicsComposerV2_1TargetTest.cpp"],
 
     // TODO(b/64437680): Assume these libs are always available on the device.
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index 1e0a329..7af0fb4 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -30,6 +30,10 @@
         // Needed for librenderengine
         "skia_deps",
     ],
+    tidy_timeout_srcs: [
+        "VtsHalGraphicsComposerV2_2ReadbackTest.cpp",
+        "VtsHalGraphicsComposerV2_2TargetTest.cpp",
+    ],
     srcs: [
         "VtsHalGraphicsComposerV2_2ReadbackTest.cpp",
         "VtsHalGraphicsComposerV2_2TargetTest.cpp",
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
index d27a151..70384ac 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -26,6 +26,7 @@
 cc_test {
     name: "VtsHalGraphicsComposerV2_3TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: ["VtsHalGraphicsComposerV2_3TargetTest.cpp"],
     srcs: ["VtsHalGraphicsComposerV2_3TargetTest.cpp"],
 
     // TODO(b/64437680): Assume these libs are always available on the device.
diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp
index 6089e2d..22ae7c4 100644
--- a/graphics/composer/2.4/vts/functional/Android.bp
+++ b/graphics/composer/2.4/vts/functional/Android.bp
@@ -26,6 +26,7 @@
 cc_test {
     name: "VtsHalGraphicsComposerV2_4TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: ["VtsHalGraphicsComposerV2_4TargetTest.cpp"],
     srcs: ["VtsHalGraphicsComposerV2_4TargetTest.cpp"],
 
     // TODO(b/64437680): Assume these libs are always available on the device.
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl
index 9c49583..b89f7d5 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl
@@ -39,4 +39,5 @@
   SKIP_CLIENT_COLOR_TRANSFORM = 2,
   PRESENT_FENCE_IS_NOT_RELIABLE = 3,
   SKIP_VALIDATE = 4,
+  BOOT_DISPLAY_CONFIG = 5,
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTargetPropertyWithNits.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl
similarity index 92%
rename from graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTargetPropertyWithNits.aidl
rename to graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl
index f0fb22e..8fb6933 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTargetPropertyWithNits.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl
@@ -33,8 +33,9 @@
 
 package android.hardware.graphics.composer3;
 @VintfStability
-parcelable ClientTargetPropertyWithNits {
+parcelable ClientTargetPropertyWithBrightness {
   long display;
   android.hardware.graphics.composer3.ClientTargetProperty clientTargetProperty;
-  float whitePointNits;
+  float brightness;
+  android.hardware.graphics.composer3.DimmingStage dimmingStage;
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl
index ebbb31e..6892f06 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl
@@ -40,5 +40,5 @@
   android.hardware.graphics.composer3.PresentFence presentFence;
   android.hardware.graphics.composer3.ReleaseFences releaseFences;
   android.hardware.graphics.composer3.PresentOrValidate presentOrValidateResult;
-  android.hardware.graphics.composer3.ClientTargetPropertyWithNits clientTargetProperty;
+  android.hardware.graphics.composer3.ClientTargetPropertyWithBrightness clientTargetProperty;
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Luminance.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DimmingStage.aidl
similarity index 91%
copy from graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Luminance.aidl
copy to graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DimmingStage.aidl
index adb49a8..44457f8 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Luminance.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DimmingStage.aidl
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2021, The Android Open Source Project
+ * Copyright (c) 2022, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,7 +32,9 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.graphics.composer3;
-@VintfStability
-parcelable Luminance {
-  float nits;
+@Backing(type="int") @VintfStability
+enum DimmingStage {
+  NONE = 0,
+  LINEAR = 1,
+  GAMMA_OETF = 2,
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayBrightness.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayBrightness.aidl
index be623df..e765189 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayBrightness.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayBrightness.aidl
@@ -35,4 +35,5 @@
 @VintfStability
 parcelable DisplayBrightness {
   float brightness;
+  float brightnessNits;
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposer.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposer.aidl
index 9abc608..21b9ad8 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposer.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposer.aidl
@@ -35,7 +35,6 @@
 @VintfStability
 interface IComposer {
   android.hardware.graphics.composer3.IComposerClient createClient();
-  String dumpDebugInfo();
   android.hardware.graphics.composer3.Capability[] getCapabilities();
   const int EX_NO_RESOURCES = 6;
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Luminance.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerBrightness.aidl
similarity index 96%
rename from graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Luminance.aidl
rename to graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerBrightness.aidl
index adb49a8..a726cc1 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Luminance.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerBrightness.aidl
@@ -33,6 +33,6 @@
 
 package android.hardware.graphics.composer3;
 @VintfStability
-parcelable Luminance {
-  float nits;
+parcelable LayerBrightness {
+  float brightness;
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
index c1c0117..0c5fac9 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
@@ -50,7 +50,7 @@
   @nullable android.hardware.graphics.common.Rect[] visibleRegion;
   @nullable android.hardware.graphics.composer3.ZOrder z;
   @nullable float[] colorTransform;
-  @nullable android.hardware.graphics.composer3.Luminance whitePointNits;
+  @nullable android.hardware.graphics.composer3.LayerBrightness brightness;
   @nullable android.hardware.graphics.composer3.PerFrameMetadata[] perFrameMetadata;
   @nullable android.hardware.graphics.composer3.PerFrameMetadataBlob[] perFrameMetadataBlob;
   @nullable android.hardware.graphics.common.Rect[] blockingRegion;
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl
index ea619ae..2f9eab9 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl
@@ -57,4 +57,13 @@
      * validateDisplay step is needed.
      */
     SKIP_VALIDATE = 4,
+
+    /**
+     * Specifies that the device supports setting a display configuration that
+     * the device should boot at.
+     * @see IComposerClient.setBootDisplayConfig
+     * @see IComposerClient.clearBootDisplayConfig
+     * @see IComposerClient.getPreferredBootDisplayConfig
+     */
+    BOOT_DISPLAY_CONFIG = 5,
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl
new file mode 100644
index 0000000..ba6fe97
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.aidl
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+import android.hardware.graphics.composer3.ClientTargetProperty;
+import android.hardware.graphics.composer3.DimmingStage;
+
+@VintfStability
+parcelable ClientTargetPropertyWithBrightness {
+    /**
+     * The display which this commands refers to.
+     * @see IComposer.createDisplay
+     */
+    long display;
+
+    /**
+     * The Client target property.
+     */
+    ClientTargetProperty clientTargetProperty;
+
+    /**
+     * The brightness as described in CommandResultPayload.clientTargetProperty
+     */
+    float brightness;
+
+    /**
+     * The stage in which dimming operations should be performed when compositing
+     * the client target.
+     * Note that with a COLORIMETRIC RenderIntent, DimmingSpace must be LINEAR. That is, dimming
+     * is defined to occur in linear space.
+     * However, some composer implementations may, with other vendor-defined RenderIntents,
+     * configure their hardware such as image quality adjustments is intended to occur after
+     * composition. In this scenario, if the dimming operation were applied in linear space,
+     * then the resulting dimming operation may comepl those image quality adjustments to
+     * incorrectly alter the gamma curve. To avoid this issue, those implementations must opt to
+     * dim in gamma space.
+     */
+    DimmingStage dimmingStage;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithNits.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithNits.aidl
deleted file mode 100644
index 5037651..0000000
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithNits.aidl
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.graphics.composer3;
-
-import android.hardware.graphics.composer3.ClientTargetProperty;
-
-@VintfStability
-parcelable ClientTargetPropertyWithNits {
-    /**
-     * The display which this commands refers to.
-     * @see IComposer.createDisplay
-     */
-    long display;
-
-    /**
-     * The Client target property.
-     */
-    ClientTargetProperty clientTargetProperty;
-
-    /**
-     * The white points nits as described in CommandResultPayload.clientTargetProperty
-     */
-    float whitePointNits;
-}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl
index f2de68e..106fd87 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl
@@ -17,7 +17,7 @@
 package android.hardware.graphics.composer3;
 
 import android.hardware.graphics.composer3.ChangedCompositionTypes;
-import android.hardware.graphics.composer3.ClientTargetPropertyWithNits;
+import android.hardware.graphics.composer3.ClientTargetPropertyWithBrightness;
 import android.hardware.graphics.composer3.CommandError;
 import android.hardware.graphics.composer3.DisplayRequest;
 import android.hardware.graphics.composer3.PresentFence;
@@ -83,12 +83,13 @@
     PresentOrValidate presentOrValidateResult;
 
     /**
-     * The white point parameter describes the intended white point of the client target buffer.
+     * The brightness parameter describes the intended brightness space of the client target buffer.
+     * The brightness is in the range [0, 1], where 1 is the current brightness of the display.
      * When client composition blends both HDR and SDR content, the client must composite to the
      * brightness space as specified by the hardware composer. This is so that adjusting the real
      * display brightness may be applied atomically with compensating the client target output. For
      * instance, client-compositing a list of SDR layers requires dimming the brightness space of
      * the SDR buffers when an HDR layer is simultaneously device-composited.
      */
-    ClientTargetPropertyWithNits clientTargetProperty;
+    ClientTargetPropertyWithBrightness clientTargetProperty;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Composition.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/Composition.aidl
index adcc9f6..82b218b 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/Composition.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/Composition.aidl
@@ -80,7 +80,7 @@
      *
      * Only supported if the device returns a valid struct from
      * getDisplayDecorationSupport. Pixels in the buffer are interpreted
-     * according to the DisplayDecorationSupport.alphInterpretation.
+     * according to the DisplayDecorationSupport.alphaInterpretation.
      *
      * Upon validateDisplay, the device may request a change from this type
      * to either DEVICE or CLIENT.
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DimmingStage.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DimmingStage.aidl
new file mode 100644
index 0000000..f732d41
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DimmingStage.aidl
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+@VintfStability
+@Backing(type="int")
+enum DimmingStage {
+    /**
+     * Corresponds to if the dimming stage is not meaningful for a scene, such as
+     * if client composition is not requesting dimming.
+     */
+    NONE = 0,
+    /**
+     * Dimming operations must be applied in linear optical space
+     */
+    LINEAR = 1,
+    /**
+     * Dimming operations must be applied in gamma space, after OETF has been applied
+     */
+    GAMMA_OETF = 2,
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayBrightness.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayBrightness.aidl
index f66b235..51f4db5 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayBrightness.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayBrightness.aidl
@@ -20,7 +20,16 @@
 parcelable DisplayBrightness {
     /**
      * A number between 0.0f (minimum brightness) and 1.0f (maximum brightness), a negative value to
-     * turn the backlight off.
+     * turn the backlight off
      */
     float brightness;
+
+    /**
+     * The absolute brightness in nits of the backlight, if it is available. This will be a negative
+     * value if it is not known.
+     *
+     * An implementation may choose to use this value to assist with tone-mapping, as a mapping
+     * between the brightness float and the nits may not otherwise be known.
+     */
+    float brightnessNits;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl
index f1ce1a7..b6df147 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl
@@ -77,15 +77,7 @@
      * the display brightness, for example when internally switching the display between multiple
      * power modes to achieve higher luminance. In those cases, the underlying display panel's real
      * brightness may not be applied atomically; however, layer dimming when mixing HDR and SDR
-     * content must be synchronized.
-     *
-     * As an illustrative example: suppose two layers have white
-     * points of 200 nits and 1000 nits respectively, the old display luminance is 200 nits, and the
-     * new display luminance is 1000 nits. If the new display luminance takes two frames to apply,
-     * then: In the first frame, there must not be any relative dimming of layers (treat both layers
-     * as 200 nits as the maximum luminance of the display is 200 nits). In the second frame, there
-     * dimming should be applied to ensure that the first layer does not become perceptually
-     * brighter during the transition.
+     * content must be synchronized to ensure that there is no user-perceptable flicker.
      *
      * The display luminance must be updated by this command even if there is not pending validate
      * or present command.
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposer.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposer.aidl
index b8edd80..0ebc2b7 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposer.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposer.aidl
@@ -36,14 +36,6 @@
     IComposerClient createClient();
 
     /**
-     * Retrieves implementation-defined debug information, which will be
-     * displayed during, for example, `dumpsys SurfaceFlinger`.
-     *
-     * @return is a string of debug information.
-     */
-    String dumpDebugInfo();
-
-    /**
      * Provides a list of supported capabilities (as described in the
      * definition of Capability above). This list must not change after
      * initialization.
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
index 769f803..a4ea64f 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -590,6 +590,7 @@
      *
      * @exception EX_BAD_DISPLAY when an invalid display handle was passed in.
      * @exception EX_BAD_CONFIG when an invalid config id was passed in.
+     * @exception EX_UNSUPPORTED when not supported by the underlying HAL
      *
      * @see getDisplayConfigs
      * @see clearBootDisplayConfig
@@ -605,6 +606,7 @@
      * @param display is the display for which the cached boot config is cleared.
      *
      * @exception EX_BAD_DISPLAY when an invalid display handle was passed in.
+     * @exception EX_UNSUPPORTED when not supported by the underlying HAL
      *
      * @see getDisplayConfigs
      * @see setBootDisplayConfig
@@ -622,6 +624,7 @@
      * @return the implementation's preferred display config.
      *
      * @exception EX_BAD_DISPLAY when an invalid display handle was passed in.
+     * @exception EX_UNSUPPORTED when not supported by the underlying HAL
      *
      * @see getDisplayConfigs
      * @see setBootDisplayConfig
@@ -798,7 +801,7 @@
      * idle period.
      *
      * This function should only be called if the display reports support for
-     * DisplayCapability.DISPLAY_IDLE from getDisplayCapabilities.
+     * DisplayCapability.DISPLAY_IDLE_TIMER from getDisplayCapabilities.
      *
      * @param display is the display to which the idle timer is set.
      * @param timeoutMs is the minimum requirements of idle period in milliseconds. Panel
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Luminance.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerBrightness.aidl
similarity index 76%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/Luminance.aidl
rename to graphics/composer/aidl/android/hardware/graphics/composer3/LayerBrightness.aidl
index 5b1c1b4..146e012 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/Luminance.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerBrightness.aidl
@@ -17,10 +17,10 @@
 package android.hardware.graphics.composer3;
 
 @VintfStability
-parcelable Luminance {
+parcelable LayerBrightness {
     /**
-     * Photometric measure of luminous intensity per unit area of light.
-     * Units are nits, or cd/m^2.
+     * Brightness of the current layer, ranging from 0 to 1, where 0 is the minimum brightness of
+     * the display, and 1 is the current brightness of the display.
      */
-    float nits;
+    float brightness;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
index 6f6894f..f3b67a9 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
@@ -22,7 +22,7 @@
 import android.hardware.graphics.common.Rect;
 import android.hardware.graphics.composer3.Buffer;
 import android.hardware.graphics.composer3.Color;
-import android.hardware.graphics.composer3.Luminance;
+import android.hardware.graphics.composer3.LayerBrightness;
 import android.hardware.graphics.composer3.ParcelableBlendMode;
 import android.hardware.graphics.composer3.ParcelableComposition;
 import android.hardware.graphics.composer3.ParcelableDataspace;
@@ -221,12 +221,12 @@
     @nullable float[] colorTransform;
 
     /**
-     * Sets the desired white point for the layer. This is intended to be used when presenting
-     * an SDR layer alongside HDR content. The HDR content will be presented at the display
-     * brightness in nits, and accordingly SDR content shall be dimmed to the desired white point
-     * provided.
+     * Sets the desired brightness for the layer. This is intended to be used for instance when
+     * presenting an SDR layer alongside HDR content. The HDR content will be presented at the
+     * display brightness in nits, and accordingly SDR content shall be dimmed according to the
+     * provided brightness ratio.
      */
-    @nullable Luminance whitePointNits;
+    @nullable LayerBrightness brightness;
 
     /**
      * Sets the PerFrameMetadata for the display. This metadata must be used
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
index f9e35e9..27dce76 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
@@ -153,14 +153,14 @@
     }
 
     // Get the client target properties requested by hardware composer.
-    ClientTargetPropertyWithNits takeClientTargetProperty(int64_t display) {
+    ClientTargetPropertyWithBrightness takeClientTargetProperty(int64_t display) {
         auto found = mReturnData.find(display);
 
         // If not found, return the default values.
         if (found == mReturnData.end()) {
-            return ClientTargetPropertyWithNits{
+            return ClientTargetPropertyWithBrightness{
                     .clientTargetProperty = {common::PixelFormat::RGBA_8888, Dataspace::UNKNOWN},
-                    .whitePointNits = -1.f,
+                    .brightness = 1.f,
             };
         }
 
@@ -201,7 +201,8 @@
         data.presentOrValidateState = std::move(presentOrValidate.result);
     }
 
-    void parseSetClientTargetProperty(const ClientTargetPropertyWithNits&& clientTargetProperty) {
+    void parseSetClientTargetProperty(
+            const ClientTargetPropertyWithBrightness&& clientTargetProperty) {
         auto& data = mReturnData[clientTargetProperty.display];
         data.clientTargetProperty = std::move(clientTargetProperty);
     }
@@ -213,9 +214,9 @@
         std::vector<ReleaseFences::Layer> releasedLayers;
         PresentOrValidate::Result presentOrValidateState;
 
-        ClientTargetPropertyWithNits clientTargetProperty = {
+        ClientTargetPropertyWithBrightness clientTargetProperty = {
                 .clientTargetProperty = {common::PixelFormat::RGBA_8888, Dataspace::UNKNOWN},
-                .whitePointNits = -1.f,
+                .brightness = 1.f,
         };
     };
 
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
index a04b982..ae17c51 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
@@ -30,7 +30,7 @@
 #include <aidl/android/hardware/graphics/composer3/Color.h>
 #include <aidl/android/hardware/graphics/composer3/Composition.h>
 #include <aidl/android/hardware/graphics/composer3/DisplayBrightness.h>
-#include <aidl/android/hardware/graphics/composer3/Luminance.h>
+#include <aidl/android/hardware/graphics/composer3/LayerBrightness.h>
 #include <aidl/android/hardware/graphics/composer3/PerFrameMetadata.h>
 #include <aidl/android/hardware/graphics/composer3/PerFrameMetadataBlob.h>
 
@@ -209,8 +209,9 @@
                 .perFrameMetadataBlob.emplace(metadata.begin(), metadata.end());
     }
 
-    void setLayerWhitePointNits(int64_t display, int64_t layer, float whitePointNits) {
-        getLayerCommand(display, layer).whitePointNits.emplace(Luminance{.nits = whitePointNits});
+    void setLayerBrightness(int64_t display, int64_t layer, float brightness) {
+        getLayerCommand(display, layer)
+                .brightness.emplace(LayerBrightness{.brightness = brightness});
     }
 
     void setLayerBlockingRegion(int64_t display, int64_t layer, const std::vector<Rect>& blocking) {
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/Android.bp b/graphics/composer/aidl/vts/Android.bp
similarity index 93%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/Android.bp
rename to graphics/composer/aidl/vts/Android.bp
index 139b5e8..1e70a0e 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/Android.bp
+++ b/graphics/composer/aidl/vts/Android.bp
@@ -34,10 +34,10 @@
     srcs: [
         "VtsHalGraphicsComposer3_TargetTest.cpp",
         "VtsHalGraphicsComposer3_ReadbackTest.cpp",
-        "composer-vts/GraphicsComposerCallback.cpp",
-        "composer-vts/ReadbackVts.cpp",
-        "composer-vts/RenderEngineVts.cpp",
-        "composer-vts/VtsComposerClient.cpp",
+        "GraphicsComposerCallback.cpp",
+        "ReadbackVts.cpp",
+        "RenderEngineVts.cpp",
+        "VtsComposerClient.cpp",
     ],
 
     shared_libs: [
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/AndroidTest.xml b/graphics/composer/aidl/vts/AndroidTest.xml
similarity index 100%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/AndroidTest.xml
rename to graphics/composer/aidl/vts/AndroidTest.xml
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/GraphicsComposerCallback.cpp b/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp
similarity index 81%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/GraphicsComposerCallback.cpp
rename to graphics/composer/aidl/vts/GraphicsComposerCallback.cpp
index 22b5d79..d534943 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/GraphicsComposerCallback.cpp
+++ b/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "include/GraphicsComposerCallback.h"
+#include "GraphicsComposerCallback.h"
 #include <log/log_main.h>
 #include <utils/Timers.h>
 
@@ -31,7 +31,7 @@
 
 std::vector<int64_t> GraphicsComposerCallback::getDisplays() const {
     std::scoped_lock lock(mMutex);
-    return std::vector<int64_t>(mDisplays.begin(), mDisplays.end());
+    return mDisplays;
 }
 
 int32_t GraphicsComposerCallback::getInvalidHotplugCount() const {
@@ -81,22 +81,29 @@
 
 ::ndk::ScopedAStatus GraphicsComposerCallback::onHotplug(int64_t in_display, bool in_connected) {
     std::scoped_lock lock(mMutex);
+
+    const auto it = std::find(mDisplays.begin(), mDisplays.end(), in_display);
     if (in_connected) {
-        if (!mDisplays.insert(in_display).second) {
+        if (it == mDisplays.end()) {
+            mDisplays.push_back(in_display);
+        } else {
             mInvalidHotplugCount++;
         }
     } else {
-        if (!mDisplays.erase(in_display)) {
+        if (it != mDisplays.end()) {
+            mDisplays.erase(it);
+        } else {
             mInvalidHotplugCount++;
         }
     }
     return ::ndk::ScopedAStatus::ok();
 }
 
-::ndk::ScopedAStatus GraphicsComposerCallback::onRefresh(int64_t display) {
+::ndk::ScopedAStatus GraphicsComposerCallback::onRefresh(int64_t in_display) {
     std::scoped_lock lock(mMutex);
 
-    if (mDisplays.count(display) == 0) {
+    const auto it = std::find(mDisplays.begin(), mDisplays.end(), in_display);
+    if (it == mDisplays.end()) {
         mInvalidRefreshCount++;
     }
 
@@ -106,7 +113,9 @@
 ::ndk::ScopedAStatus GraphicsComposerCallback::onVsync(int64_t in_display, int64_t in_timestamp,
                                                        int32_t in_vsyncPeriodNanos) {
     std::scoped_lock lock(mMutex);
-    if (!mVsyncAllowed || mDisplays.count(in_display) == 0) {
+
+    const auto it = std::find(mDisplays.begin(), mDisplays.end(), in_display);
+    if (!mVsyncAllowed || it == mDisplays.end()) {
         mInvalidVsyncCount++;
     }
 
@@ -120,7 +129,9 @@
         const ::aidl::android::hardware::graphics::composer3::VsyncPeriodChangeTimeline&
                 in_updatedTimeline) {
     std::scoped_lock lock(mMutex);
-    if (mDisplays.count(in_display) == 0) {
+
+    const auto it = std::find(mDisplays.begin(), mDisplays.end(), in_display);
+    if (it == mDisplays.end()) {
         mInvalidVsyncPeriodChangeCount++;
     }
     mTimeline = in_updatedTimeline;
@@ -130,7 +141,9 @@
 
 ::ndk::ScopedAStatus GraphicsComposerCallback::onSeamlessPossible(int64_t in_display) {
     std::scoped_lock lock(mMutex);
-    if (mDisplays.count(in_display)) {
+
+    const auto it = std::find(mDisplays.begin(), mDisplays.end(), in_display);
+    if (it != mDisplays.end()) {
         mInvalidSeamlessPossibleCount++;
     }
     return ::ndk::ScopedAStatus::ok();
@@ -138,7 +151,9 @@
 
 ::ndk::ScopedAStatus GraphicsComposerCallback::onVsyncIdle(int64_t in_display) {
     std::scoped_lock lock(mMutex);
-    if (mDisplays.count(in_display)) {
+
+    const auto it = std::find(mDisplays.begin(), mDisplays.end(), in_display);
+    if (it != mDisplays.end()) {
         mVsyncIdleCount++;
         mVsyncIdleTime = systemTime();
     }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/GraphicsComposerCallback.h b/graphics/composer/aidl/vts/GraphicsComposerCallback.h
similarity index 96%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/GraphicsComposerCallback.h
rename to graphics/composer/aidl/vts/GraphicsComposerCallback.h
index ced1020..e54da34 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/GraphicsComposerCallback.h
+++ b/graphics/composer/aidl/vts/GraphicsComposerCallback.h
@@ -18,7 +18,7 @@
 #include <aidl/android/hardware/graphics/composer3/BnComposerCallback.h>
 #include <android-base/thread_annotations.h>
 #include <mutex>
-#include <unordered_set>
+#include <vector>
 
 namespace aidl::android::hardware::graphics::composer3::vts {
 
@@ -58,7 +58,7 @@
 
     mutable std::mutex mMutex;
     // the set of all currently connected displays
-    std::unordered_set<int64_t> mDisplays GUARDED_BY(mMutex);
+    std::vector<int64_t> mDisplays GUARDED_BY(mMutex);
     // true only when vsync is enabled
     bool mVsyncAllowed GUARDED_BY(mMutex) = true;
 
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/OWNERS b/graphics/composer/aidl/vts/OWNERS
similarity index 100%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/OWNERS
rename to graphics/composer/aidl/vts/OWNERS
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/ReadbackVts.cpp b/graphics/composer/aidl/vts/ReadbackVts.cpp
similarity index 94%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/ReadbackVts.cpp
rename to graphics/composer/aidl/vts/ReadbackVts.cpp
index 1aca76f..03b1b6c 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/ReadbackVts.cpp
+++ b/graphics/composer/aidl/vts/ReadbackVts.cpp
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#include "include/ReadbackVts.h"
+#include "ReadbackVts.h"
 #include <aidl/android/hardware/graphics/common/BufferUsage.h>
-#include "include/RenderEngineVts.h"
+#include "RenderEngineVts.h"
 #include "renderengine/ExternalTexture.h"
 #include "renderengine/impl/ExternalTexture.h"
 
@@ -34,7 +34,7 @@
     writer.setLayerTransform(mDisplay, mLayer, mTransform);
     writer.setLayerPlaneAlpha(mDisplay, mLayer, mAlpha);
     writer.setLayerBlendMode(mDisplay, mLayer, mBlendMode);
-    writer.setLayerWhitePointNits(mDisplay, mLayer, mWhitePointNits);
+    writer.setLayerBrightness(mDisplay, mLayer, mBrightness);
 }
 
 std::string ReadbackHelper::getColorModeString(ColorMode mode) {
@@ -209,14 +209,14 @@
     mAccessRegion.bottom = static_cast<int32_t>(height);
 }
 
-::android::sp<::android::GraphicBuffer> ReadbackBuffer::allocate() {
+::android::sp<::android::GraphicBuffer> ReadbackBuffer::allocateBuffer() {
     return ::android::sp<::android::GraphicBuffer>::make(
             mWidth, mHeight, static_cast<::android::PixelFormat>(mPixelFormat), mLayerCount, mUsage,
-            "ReadbackVts");
+            "ReadbackBuffer");
 }
 
 void ReadbackBuffer::setReadbackBuffer() {
-    mGraphicBuffer = allocate();
+    mGraphicBuffer = allocateBuffer();
     ASSERT_NE(nullptr, mGraphicBuffer);
     ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
     const auto& bufferHandle = mGraphicBuffer->handle;
@@ -262,12 +262,10 @@
 }
 
 TestBufferLayer::TestBufferLayer(const std::shared_ptr<VtsComposerClient>& client,
-                                 const ::android::sp<::android::GraphicBuffer>& graphicBuffer,
                                  TestRenderEngine& renderEngine, int64_t display, uint32_t width,
                                  uint32_t height, common::PixelFormat format,
                                  Composition composition)
     : TestLayer{client, display}, mRenderEngine(renderEngine) {
-    mGraphicBuffer = graphicBuffer;
     mComposition = composition;
     mWidth = width;
     mHeight = height;
@@ -290,8 +288,9 @@
     TestLayer::write(writer);
     writer.setLayerCompositionType(mDisplay, mLayer, mComposition);
     writer.setLayerVisibleRegion(mDisplay, mLayer, std::vector<Rect>(1, mDisplayFrame));
-    if (mGraphicBuffer->handle != nullptr)
-        writer.setLayerBuffer(mDisplay, mLayer, 0, mGraphicBuffer->handle, mFillFence);
+    if (mGraphicBuffer) {
+        writer.setLayerBuffer(mDisplay, mLayer, /*slot*/ 0, mGraphicBuffer->handle, mFillFence);
+    }
 }
 
 LayerSettings TestBufferLayer::toRenderEngineLayerSettings() {
@@ -326,16 +325,22 @@
     EXPECT_EQ(::android::OK, status);
     ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mWidth, mHeight, stride, bufData,
                                                        mPixelFormat, expectedColors));
-    EXPECT_EQ(::android::OK, mGraphicBuffer->unlock());
+
+    const auto unlockStatus = mGraphicBuffer->unlockAsync(&mFillFence);
+    ASSERT_EQ(::android::OK, unlockStatus);
 }
 
 void TestBufferLayer::setBuffer(std::vector<Color> colors) {
-    mGraphicBuffer->reallocate(mWidth, mHeight, static_cast<::android::PixelFormat>(mPixelFormat),
-                               mLayerCount, mUsage);
+    mGraphicBuffer = allocateBuffer();
     ASSERT_NE(nullptr, mGraphicBuffer);
-    ASSERT_NE(nullptr, mGraphicBuffer->handle);
-    ASSERT_NO_FATAL_FAILURE(fillBuffer(colors));
     ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
+    ASSERT_NO_FATAL_FAILURE(fillBuffer(colors));
+}
+
+::android::sp<::android::GraphicBuffer> TestBufferLayer::allocateBuffer() {
+    return ::android::sp<::android::GraphicBuffer>::make(
+            mWidth, mHeight, static_cast<::android::PixelFormat>(mPixelFormat), mLayerCount, mUsage,
+            "TestBufferLayer");
 }
 
 void TestBufferLayer::setDataspace(common::Dataspace dataspace, ComposerClientWriter& writer) {
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/ReadbackVts.h b/graphics/composer/aidl/vts/ReadbackVts.h
similarity index 95%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/ReadbackVts.h
rename to graphics/composer/aidl/vts/ReadbackVts.h
index 7135dca..ee9f0d5 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/ReadbackVts.h
+++ b/graphics/composer/aidl/vts/ReadbackVts.h
@@ -67,6 +67,7 @@
     void setSourceCrop(FRect crop) { mSourceCrop = crop; }
     void setZOrder(uint32_t z) { mZOrder = z; }
     void setWhitePointNits(float whitePointNits) { mWhitePointNits = whitePointNits; }
+    void setBrightness(float brightness) { mBrightness = brightness; }
 
     void setSurfaceDamage(std::vector<Rect> surfaceDamage) {
         mSurfaceDamage = std::move(surfaceDamage);
@@ -84,12 +85,13 @@
 
     int64_t getLayer() const { return mLayer; }
 
-    float getWhitePointNits() const { return mWhitePointNits; }
+    float getBrightness() const { return mBrightness; }
 
   protected:
     int64_t mDisplay;
     int64_t mLayer;
     Rect mDisplayFrame = {0, 0, 0, 0};
+    float mBrightness = 1.f;
     float mWhitePointNits = -1.f;
     std::vector<Rect> mSurfaceDamage;
     Transform mTransform = static_cast<Transform>(0);
@@ -118,7 +120,6 @@
 class TestBufferLayer : public TestLayer {
   public:
     TestBufferLayer(const std::shared_ptr<VtsComposerClient>& client,
-                    const ::android::sp<::android::GraphicBuffer>& graphicBuffer,
                     TestRenderEngine& renderEngine, int64_t display, uint32_t width,
                     uint32_t height, common::PixelFormat format,
                     Composition composition = Composition::DEVICE);
@@ -154,6 +155,9 @@
     PixelFormat mPixelFormat;
     uint32_t mUsage;
     ::android::Rect mAccessRegion;
+
+  private:
+    ::android::sp<::android::GraphicBuffer> allocateBuffer();
 };
 
 class ReadbackHelper {
@@ -194,8 +198,6 @@
 
     void checkReadbackBuffer(const std::vector<Color>& expectedColors);
 
-    ::android::sp<::android::GraphicBuffer> allocate();
-
   protected:
     uint32_t mWidth;
     uint32_t mHeight;
@@ -208,6 +210,9 @@
     std::shared_ptr<VtsComposerClient> mComposerClient;
     ::android::Rect mAccessRegion;
     native_handle_t mBufferHandle;
+
+  private:
+    ::android::sp<::android::GraphicBuffer> allocateBuffer();
 };
 
 }  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/RenderEngineVts.cpp b/graphics/composer/aidl/vts/RenderEngineVts.cpp
similarity index 98%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/RenderEngineVts.cpp
rename to graphics/composer/aidl/vts/RenderEngineVts.cpp
index 0a55484..71b011c 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/RenderEngineVts.cpp
+++ b/graphics/composer/aidl/vts/RenderEngineVts.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "include/RenderEngineVts.h"
+#include "RenderEngineVts.h"
 #include "renderengine/impl/ExternalTexture.h"
 
 namespace aidl::android::hardware::graphics::composer3::vts {
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/RenderEngineVts.h b/graphics/composer/aidl/vts/RenderEngineVts.h
similarity index 100%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/RenderEngineVts.h
rename to graphics/composer/aidl/vts/RenderEngineVts.h
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/VtsComposerClient.cpp b/graphics/composer/aidl/vts/VtsComposerClient.cpp
similarity index 96%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/VtsComposerClient.cpp
rename to graphics/composer/aidl/vts/VtsComposerClient.cpp
index 8c882d0..2b60703 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/VtsComposerClient.cpp
+++ b/graphics/composer/aidl/vts/VtsComposerClient.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "include/VtsComposerClient.h"
+#include "VtsComposerClient.h"
 #include <aidlcommonsupport/NativeHandle.h>
 #include <android-base/logging.h>
 #include <log/log_main.h>
@@ -173,8 +173,15 @@
 }
 
 ScopedAStatus VtsComposerClient::dumpDebugInfo() {
-    std::string debugInfo;
-    return mComposer->dumpDebugInfo(&debugInfo);
+    int pipefds[2];
+    if (pipe(pipefds) < 0) {
+        return ScopedAStatus::fromServiceSpecificError(IComposer::EX_NO_RESOURCES);
+    }
+
+    const auto status = mComposer->dump(pipefds[1], /*args*/ nullptr, /*numArgs*/ 0);
+    close(pipefds[0]);
+    close(pipefds[1]);
+    return ScopedAStatus::fromStatus(status);
 }
 
 std::pair<ScopedAStatus, DisplayIdentification> VtsComposerClient::getDisplayIdentificationData(
@@ -283,6 +290,12 @@
     return {mComposerClient->getSupportedContentTypes(display, &outContentTypes), outContentTypes};
 }
 
+std::pair<ScopedAStatus, std::optional<DisplayDecorationSupport>>
+VtsComposerClient::getDisplayDecorationSupport(int64_t display) {
+    std::optional<DisplayDecorationSupport> outSupport;
+    return {mComposerClient->getDisplayDecorationSupport(display, &outSupport), outSupport};
+}
+
 std::pair<ScopedAStatus, int32_t> VtsComposerClient::getMaxVirtualDisplayCount() {
     int32_t outMaxVirtualDisplayCount;
     return {mComposerClient->getMaxVirtualDisplayCount(&outMaxVirtualDisplayCount),
@@ -499,4 +512,4 @@
     mDisplayResources.clear();
     return true;
 }
-}  // namespace aidl::android::hardware::graphics::composer3::vts
\ No newline at end of file
+}  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/VtsComposerClient.h b/graphics/composer/aidl/vts/VtsComposerClient.h
similarity index 97%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/VtsComposerClient.h
rename to graphics/composer/aidl/vts/VtsComposerClient.h
index 9af867c..3625c8c 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/VtsComposerClient.h
+++ b/graphics/composer/aidl/vts/VtsComposerClient.h
@@ -38,6 +38,7 @@
 #include "GraphicsComposerCallback.h"
 
 using aidl::android::hardware::graphics::common::Dataspace;
+using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
 using aidl::android::hardware::graphics::common::FRect;
 using aidl::android::hardware::graphics::common::PixelFormat;
 using aidl::android::hardware::graphics::common::Rect;
@@ -142,6 +143,9 @@
 
     std::pair<ScopedAStatus, std::vector<ContentType>> getSupportedContentTypes(int64_t display);
 
+    std::pair<ScopedAStatus, std::optional<DisplayDecorationSupport>> getDisplayDecorationSupport(
+            int64_t display);
+
     std::pair<ScopedAStatus, int32_t> getMaxVirtualDisplayCount();
 
     std::pair<ScopedAStatus, std::string> getDisplayName(int64_t display);
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
similarity index 88%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp
rename to graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 45a8f6f..147a9ee 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -20,22 +20,22 @@
 #include <aidl/Vintf.h>
 #include <aidl/android/hardware/graphics/common/BufferUsage.h>
 #include <aidl/android/hardware/graphics/composer3/IComposer.h>
-#include <composer-vts/include/ReadbackVts.h>
-#include <composer-vts/include/RenderEngineVts.h>
 #include <gtest/gtest.h>
 #include <ui/DisplayId.h>
 #include <ui/DisplayIdentification.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/PixelFormat.h>
 #include <ui/Rect.h>
+#include "GraphicsComposerCallback.h"
+#include "ReadbackVts.h"
+#include "RenderEngineVts.h"
+#include "VtsComposerClient.h"
 
 // tinyxml2 does implicit conversions >:(
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wconversion"
 #include <tinyxml2.h>
 #pragma clang diagnostic pop
-#include "composer-vts/include/GraphicsComposerCallback.h"
-#include "composer-vts/include/VtsComposerClient.h"
 
 namespace aidl::android::hardware::graphics::composer3::vts {
 namespace {
@@ -62,9 +62,6 @@
         }
         mComposerClient->setVsyncAllowed(/*isAllowed*/ false);
 
-        // set up gralloc
-        mGraphicBuffer = allocate();
-
         EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::ON).isOk());
 
         ASSERT_NO_FATAL_FAILURE(
@@ -112,15 +109,18 @@
 
     int32_t getDisplayHeight() const { return getPrimaryDisplay().getDisplayHeight(); }
 
-    ::android::sp<::android::GraphicBuffer> allocate() {
+    std::pair<bool, ::android::sp<::android::GraphicBuffer>> allocateBuffer(uint32_t usage) {
         const auto width = static_cast<uint32_t>(getDisplayWidth());
         const auto height = static_cast<uint32_t>(getDisplayHeight());
-        const auto usage = static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
-                           static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN);
 
-        return ::android::sp<::android::GraphicBuffer>::make(
+        const auto& graphicBuffer = ::android::sp<::android::GraphicBuffer>::make(
                 width, height, ::android::PIXEL_FORMAT_RGBA_8888,
                 /*layerCount*/ 1u, usage, "VtsHalGraphicsComposer3_ReadbackTest");
+
+        if (graphicBuffer && ::android::OK == graphicBuffer->initCheck()) {
+            return {true, graphicBuffer};
+        }
+        return {false, graphicBuffer};
     }
 
     uint64_t getStableDisplayId(int64_t display) {
@@ -214,15 +214,16 @@
         mWriter.reset();
     }
 
-    std::pair<ScopedAStatus, bool> getHasReadbackBuffer() {
+    bool getHasReadbackBuffer() {
         auto [status, readBackBufferAttributes] =
                 mComposerClient->getReadbackBufferAttributes(getPrimaryDisplayId());
         if (status.isOk()) {
             mPixelFormat = readBackBufferAttributes.format;
             mDataspace = readBackBufferAttributes.dataspace;
-            return {std::move(status), ReadbackHelper::readbackSupported(mPixelFormat, mDataspace)};
+            return ReadbackHelper::readbackSupported(mPixelFormat, mDataspace);
         }
-        return {std::move(status), false};
+        EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, status.getServiceSpecificError());
+        return false;
     }
 
     std::shared_ptr<VtsComposerClient> mComposerClient;
@@ -231,7 +232,6 @@
     std::vector<ColorMode> mTestColorModes;
     ComposerClientWriter mWriter;
     ComposerClientReader mReader;
-    ::android::sp<::android::GraphicBuffer> mGraphicBuffer;
     std::unique_ptr<TestRenderEngine> mTestRenderEngine;
     common::PixelFormat mPixelFormat;
     common::Dataspace mDataspace;
@@ -265,8 +265,8 @@
                             ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
                             .isOk());
 
-        const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-        EXPECT_TRUE(readbackStatus.isOk());
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
         if (!isSupported) {
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
@@ -317,8 +317,8 @@
                             ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
                             .isOk());
 
-        const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-        EXPECT_TRUE(readbackStatus.isOk());
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
         if (!isSupported) {
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
@@ -339,8 +339,8 @@
                 {0, getDisplayHeight() / 2, getDisplayWidth(), getDisplayHeight()}, BLUE);
 
         auto layer = std::make_shared<TestBufferLayer>(
-                mComposerClient, mGraphicBuffer, *mTestRenderEngine, getPrimaryDisplayId(),
-                getDisplayWidth(), getDisplayHeight(), common::PixelFormat::RGBA_8888);
+                mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(),
+                getDisplayHeight(), common::PixelFormat::RGBA_8888);
         layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setZOrder(10);
         layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
@@ -377,8 +377,8 @@
                             ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
                             .isOk());
 
-        const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-        EXPECT_TRUE(readbackStatus.isOk());
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
         if (!isSupported) {
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
@@ -392,15 +392,12 @@
         layer->write(mWriter);
 
         // This following buffer call should have no effect
-        uint64_t usage =
-                static_cast<uint64_t>(static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
-                                      static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN));
-
-        mGraphicBuffer->reallocate(static_cast<uint32_t>(getDisplayWidth()),
-                                   static_cast<uint32_t>(getDisplayHeight()), 1,
-                                   static_cast<uint32_t>(common::PixelFormat::RGBA_8888), usage);
-        mWriter.setLayerBuffer(getPrimaryDisplayId(), layer->getLayer(), /*slot*/ 0,
-                               mGraphicBuffer->handle,
+        const auto usage = static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
+                           static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN);
+        const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(usage);
+        ASSERT_TRUE(graphicBufferStatus);
+        const auto& buffer = graphicBuffer->handle;
+        mWriter.setLayerBuffer(getPrimaryDisplayId(), layer->getLayer(), /*slot*/ 0, buffer,
                                /*acquireFence*/ -1);
 
         // expected color for each pixel
@@ -429,8 +426,8 @@
 }
 
 TEST_P(GraphicsCompositionTest, SetReadbackBuffer) {
-    const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-    EXPECT_TRUE(readbackStatus.isOk());
+    bool isSupported;
+    ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
     if (!isSupported) {
         GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
         return;
@@ -443,16 +440,18 @@
 }
 
 TEST_P(GraphicsCompositionTest, SetReadbackBuffer_BadDisplay) {
-    const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-    EXPECT_TRUE(readbackStatus.isOk());
+    bool isSupported;
+    ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
     if (!isSupported) {
         GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
         return;
     }
 
-    ASSERT_NE(nullptr, mGraphicBuffer);
-    ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
-    const auto& bufferHandle = mGraphicBuffer->handle;
+    const auto usage = static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
+                       static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN);
+    const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(usage);
+    ASSERT_TRUE(graphicBufferStatus);
+    const auto& bufferHandle = graphicBuffer->handle;
     ::ndk::ScopedFileDescriptor fence = ::ndk::ScopedFileDescriptor(-1);
 
     const auto status =
@@ -463,8 +462,8 @@
 }
 
 TEST_P(GraphicsCompositionTest, SetReadbackBuffer_BadParameter) {
-    const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-    EXPECT_TRUE(readbackStatus.isOk());
+    bool isSupported;
+    ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
     if (!isSupported) {
         GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
         return;
@@ -480,8 +479,8 @@
 }
 
 TEST_P(GraphicsCompositionTest, GetReadbackBufferFenceInactive) {
-    const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-    EXPECT_TRUE(readbackStatus.isOk());
+    bool isSupported;
+    ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
     if (!isSupported) {
         GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
         return;
@@ -505,8 +504,8 @@
                             ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
                             .isOk());
 
-        const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-        EXPECT_TRUE(readbackStatus.isOk());
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
         if (!isSupported) {
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
@@ -523,9 +522,9 @@
                 expectedColors, getDisplayWidth(),
                 {0, getDisplayHeight() / 2, getDisplayWidth(), getDisplayHeight()}, BLUE);
 
-        auto layer = std::make_shared<TestBufferLayer>(
-                mComposerClient, mGraphicBuffer, *mTestRenderEngine, getPrimaryDisplayId(),
-                getDisplayWidth(), getDisplayHeight(), PixelFormat::RGBA_FP16);
+        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine,
+                                                       getPrimaryDisplayId(), getDisplayWidth(),
+                                                       getDisplayHeight(), PixelFormat::RGBA_FP16);
         layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setZOrder(10);
         layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
@@ -554,30 +553,23 @@
             common::Rect damage{0, 0, getDisplayWidth(), getDisplayHeight()};
 
             // create client target buffer
-            mGraphicBuffer->reallocate(layer->getWidth(), layer->getHeight(),
-                                       static_cast<int32_t>(common::PixelFormat::RGBA_8888),
-                                       layer->getLayerCount(), clientUsage);
-
-            ASSERT_NE(nullptr, mGraphicBuffer->handle);
-
+            const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(clientUsage);
+            ASSERT_TRUE(graphicBufferStatus);
+            const auto& buffer = graphicBuffer->handle;
             void* clientBufData;
-            mGraphicBuffer->lock(clientUsage, layer->getAccessRegion(), &clientBufData);
+            const auto stride = static_cast<uint32_t>(graphicBuffer->stride);
+            graphicBuffer->lock(clientUsage, layer->getAccessRegion(), &clientBufData);
 
             ASSERT_NO_FATAL_FAILURE(
-                    ReadbackHelper::fillBuffer(layer->getWidth(), layer->getHeight(),
-                                               static_cast<uint32_t>(mGraphicBuffer->stride),
+                    ReadbackHelper::fillBuffer(layer->getWidth(), layer->getHeight(), stride,
                                                clientBufData, clientFormat, expectedColors));
-            EXPECT_EQ(::android::OK, mGraphicBuffer->unlock());
-
-            const auto& [status, bufferFence] =
-                    mComposerClient->getReadbackBufferFence(getPrimaryDisplayId());
-            EXPECT_TRUE(status.isOk());
-
+            int32_t clientFence;
+            const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
+            ASSERT_EQ(::android::OK, unlockStatus);
+            mWriter.setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, buffer, clientFence,
+                                    clientDataspace, std::vector<common::Rect>(1, damage));
             layer->setToClientComposition(mWriter);
-            mWriter.acceptDisplayChanges(getPrimaryDisplayId());
-            mWriter.setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, mGraphicBuffer->handle,
-                                    bufferFence.get(), clientDataspace,
-                                    std::vector<common::Rect>(1, damage));
+            mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
             execute();
             changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId());
             ASSERT_TRUE(changedCompositionTypes.empty());
@@ -603,8 +595,8 @@
                             ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
                             .isOk());
 
-        const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-        EXPECT_TRUE(readbackStatus.isOk());
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
         if (!isSupported) {
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
@@ -623,8 +615,8 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         auto deviceLayer = std::make_shared<TestBufferLayer>(
-                mComposerClient, mGraphicBuffer, *mTestRenderEngine, getPrimaryDisplayId(),
-                getDisplayWidth(), getDisplayHeight() / 2, PixelFormat::RGBA_8888);
+                mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(),
+                getDisplayHeight() / 2, PixelFormat::RGBA_8888);
         std::vector<Color> deviceColors(deviceLayer->getWidth() * deviceLayer->getHeight());
         ReadbackHelper::fillColorsArea(deviceColors, static_cast<int32_t>(deviceLayer->getWidth()),
                                        {0, 0, static_cast<int32_t>(deviceLayer->getWidth()),
@@ -647,8 +639,8 @@
         int32_t clientHeight = getDisplayHeight() / 2;
 
         auto clientLayer = std::make_shared<TestBufferLayer>(
-                mComposerClient, mGraphicBuffer, *mTestRenderEngine, getPrimaryDisplayId(),
-                clientWidth, clientHeight, PixelFormat::RGBA_FP16, Composition::DEVICE);
+                mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), clientWidth,
+                clientHeight, PixelFormat::RGBA_FP16, Composition::DEVICE);
         common::Rect clientFrame = {0, getDisplayHeight() / 2, getDisplayWidth(),
                                     getDisplayHeight()};
         clientLayer->setDisplayFrame(clientFrame);
@@ -663,33 +655,27 @@
         }
         // create client target buffer
         ASSERT_EQ(Composition::CLIENT, changedCompositionTypes[0].composition);
-        mGraphicBuffer->reallocate(static_cast<uint32_t>(getDisplayWidth()),
-                                   static_cast<uint32_t>(getDisplayHeight()),
-                                   static_cast<int32_t>(common::PixelFormat::RGBA_8888),
-                                   clientLayer->getLayerCount(), clientUsage);
-        ASSERT_NE(nullptr, mGraphicBuffer->handle);
+        const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(clientUsage);
+        ASSERT_TRUE(graphicBufferStatus);
+        const auto& buffer = graphicBuffer->handle;
 
         void* clientBufData;
-        mGraphicBuffer->lock(clientUsage, {0, 0, getDisplayWidth(), getDisplayHeight()},
-                             &clientBufData);
+        graphicBuffer->lock(clientUsage, {0, 0, getDisplayWidth(), getDisplayHeight()},
+                            &clientBufData);
 
         std::vector<Color> clientColors(
                 static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
         ReadbackHelper::fillColorsArea(clientColors, getDisplayWidth(), clientFrame, RED);
         ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(
                 static_cast<uint32_t>(getDisplayWidth()), static_cast<uint32_t>(getDisplayHeight()),
-                mGraphicBuffer->getStride(), clientBufData, clientFormat, clientColors));
-        EXPECT_EQ(::android::OK, mGraphicBuffer->unlock());
-
-        const auto& [status, bufferFence] =
-                mComposerClient->getReadbackBufferFence(getPrimaryDisplayId());
-        EXPECT_TRUE(status.isOk());
-
+                graphicBuffer->getStride(), clientBufData, clientFormat, clientColors));
+        int32_t clientFence;
+        const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
+        ASSERT_EQ(::android::OK, unlockStatus);
+        mWriter.setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, buffer, clientFence,
+                                clientDataspace, std::vector<common::Rect>(1, clientFrame));
         clientLayer->setToClientComposition(mWriter);
-        mWriter.acceptDisplayChanges(getPrimaryDisplayId());
-        mWriter.setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, mGraphicBuffer->handle,
-                                bufferFence.get(), clientDataspace,
-                                std::vector<common::Rect>(1, clientFrame));
+        mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
         execute();
         changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId());
         ASSERT_TRUE(changedCompositionTypes.empty());
@@ -708,8 +694,8 @@
                             ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
                             .isOk());
 
-        const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-        EXPECT_TRUE(readbackStatus.isOk());
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
         if (!isSupported) {
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
@@ -721,9 +707,9 @@
                 static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
         ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), redRect, RED);
 
-        auto layer = std::make_shared<TestBufferLayer>(
-                mComposerClient, mGraphicBuffer, *mTestRenderEngine, getPrimaryDisplayId(),
-                getDisplayWidth(), getDisplayHeight(), PixelFormat::RGBA_8888);
+        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine,
+                                                       getPrimaryDisplayId(), getDisplayWidth(),
+                                                       getDisplayHeight(), PixelFormat::RGBA_8888);
         layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setZOrder(10);
         layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
@@ -783,8 +769,8 @@
                             ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
                             .isOk());
 
-        const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-        EXPECT_TRUE(readbackStatus.isOk());
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
         if (!isSupported) {
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
@@ -834,8 +820,8 @@
                             ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
                             .isOk());
 
-        const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-        EXPECT_TRUE(readbackStatus.isOk());
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
         if (!isSupported) {
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
@@ -849,9 +835,9 @@
                 expectedColors, getDisplayWidth(),
                 {0, getDisplayHeight() / 2, getDisplayWidth(), getDisplayHeight()}, BLUE);
 
-        auto layer = std::make_shared<TestBufferLayer>(
-                mComposerClient, mGraphicBuffer, *mTestRenderEngine, getPrimaryDisplayId(),
-                getDisplayWidth(), getDisplayHeight(), PixelFormat::RGBA_8888);
+        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine,
+                                                       getPrimaryDisplayId(), getDisplayWidth(),
+                                                       getDisplayHeight(), PixelFormat::RGBA_8888);
         layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setZOrder(10);
         layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
@@ -893,8 +879,8 @@
                             ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
                             .isOk());
 
-        const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-        EXPECT_TRUE(readbackStatus.isOk());
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
         if (!isSupported) {
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
@@ -965,7 +951,7 @@
     }
 }
 
-TEST_P(GraphicsCompositionTest, SetLayerWhitePointDims) {
+TEST_P(GraphicsCompositionTest, SetLayerBrightnessDims) {
     const auto& [status, capabilities] =
             mComposerClient->getDisplayCapabilities(getPrimaryDisplayId());
     ASSERT_TRUE(status.isOk());
@@ -997,8 +983,8 @@
                             ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
                             .isOk());
 
-        const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-        EXPECT_TRUE(readbackStatus.isOk());
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
         if (!isSupported) {
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace for "
                                "color mode: "
@@ -1013,6 +999,7 @@
         redLayer->setColor(RED);
         redLayer->setDisplayFrame(redRect);
         redLayer->setWhitePointNits(maxBrightnessNits);
+        redLayer->setBrightness(1.f);
 
         const auto dimmerRedLayer =
                 std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId());
@@ -1022,6 +1009,7 @@
         // kick into GPU composition to apply dithering when the dimming ratio is high.
         static constexpr float kDimmingRatio = 0.9f;
         dimmerRedLayer->setWhitePointNits(maxBrightnessNits * kDimmingRatio);
+        dimmerRedLayer->setBrightness(kDimmingRatio);
 
         const std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, dimmerRedLayer};
         std::vector<Color> expectedColors(
@@ -1061,6 +1049,12 @@
   public:
     void SetUp() override {
         SetUpBase(std::get<0>(GetParam()));
+        // TODO(b/219590743) we should remove the below SRGB color mode
+        // once we have the BlendMode test fix for all the versions of the ColorMode
+        mTestColorModes.erase(
+                std::remove_if(mTestColorModes.begin(), mTestColorModes.end(),
+                               [](ColorMode mode) { return mode != ColorMode::SRGB; }),
+                mTestColorModes.end());
         mBackgroundColor = BLACK;
         mTopLayerColor = RED;
     }
@@ -1083,9 +1077,9 @@
         backgroundLayer->setZOrder(0);
         backgroundLayer->setColor(mBackgroundColor);
 
-        auto layer = std::make_shared<TestBufferLayer>(
-                mComposerClient, mGraphicBuffer, *mTestRenderEngine, getPrimaryDisplayId(),
-                getDisplayWidth(), getDisplayHeight(), PixelFormat::RGBA_8888);
+        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine,
+                                                       getPrimaryDisplayId(), getDisplayWidth(),
+                                                       getDisplayHeight(), PixelFormat::RGBA_8888);
         layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
         layer->setZOrder(10);
         layer->setDataspace(Dataspace::UNKNOWN, mWriter);
@@ -1138,15 +1132,15 @@
     Color mBackgroundColor;
     Color mTopLayerColor;
 };
-
-TEST_P(GraphicsBlendModeCompositionTest, None) {
+// TODO(b/219576457) Enable tests once we have fixed the bug on composer.
+TEST_P(GraphicsBlendModeCompositionTest, DISABLED_None) {
     for (ColorMode mode : mTestColorModes) {
         EXPECT_TRUE(mComposerClient
                             ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
                             .isOk());
 
-        const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-        EXPECT_TRUE(readbackStatus.isOk());
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
         if (!isSupported) {
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
@@ -1189,8 +1183,8 @@
                             ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
                             .isOk());
 
-        const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-        EXPECT_TRUE(readbackStatus.isOk());
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
         if (!isSupported) {
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
@@ -1230,8 +1224,8 @@
                             ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
                             .isOk());
 
-        const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-        EXPECT_TRUE(readbackStatus.isOk());
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
         if (!isSupported) {
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
@@ -1283,9 +1277,9 @@
         common::Rect redRect = {0, 0, mSideLength / 2, mSideLength / 2};
         common::Rect blueRect = {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength};
 
-        mLayer = std::make_shared<TestBufferLayer>(
-                mComposerClient, mGraphicBuffer, *mTestRenderEngine, getPrimaryDisplayId(),
-                mSideLength, mSideLength, PixelFormat::RGBA_8888);
+        mLayer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine,
+                                                   getPrimaryDisplayId(), mSideLength, mSideLength,
+                                                   PixelFormat::RGBA_8888);
         mLayer->setDisplayFrame({0, 0, mSideLength, mSideLength});
         mLayer->setZOrder(10);
 
@@ -1313,8 +1307,8 @@
             return;
         }
 
-        const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-        EXPECT_TRUE(readbackStatus.isOk());
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
         if (!isSupported) {
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
@@ -1358,8 +1352,8 @@
                             ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
                             .isOk());
 
-        const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-        EXPECT_TRUE(readbackStatus.isOk());
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
         if (!isSupported) {
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
@@ -1403,8 +1397,8 @@
                             ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
                             .isOk());
 
-        const auto& [readbackStatus, isSupported] = getHasReadbackBuffer();
-        EXPECT_TRUE(readbackStatus.isOk());
+        bool isSupported;
+        ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
         if (!isSupported) {
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
similarity index 93%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
rename to graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index 17ec885..2d08ac6 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -18,6 +18,7 @@
 #include <aidl/android/hardware/graphics/common/BlendMode.h>
 #include <aidl/android/hardware/graphics/common/BufferUsage.h>
 #include <aidl/android/hardware/graphics/common/FRect.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
 #include <aidl/android/hardware/graphics/common/Rect.h>
 #include <aidl/android/hardware/graphics/composer3/Composition.h>
 #include <aidl/android/hardware/graphics/composer3/IComposer.h>
@@ -34,8 +35,8 @@
 #include <numeric>
 #include <string>
 #include <thread>
-#include "composer-vts/include/GraphicsComposerCallback.h"
-#include "composer-vts/include/VtsComposerClient.h"
+#include "GraphicsComposerCallback.h"
+#include "VtsComposerClient.h"
 
 #undef LOG_TAG
 #define LOG_TAG "VtsHalGraphicsComposer3_TargetTest"
@@ -494,6 +495,10 @@
 }
 
 TEST_P(GraphicsComposerAidlTest, SetBootDisplayConfig_BadDisplay) {
+    if (!hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
+        GTEST_SUCCEED() << "Boot Display Config not supported";
+        return;
+    }
     const auto& status = mComposerClient->setBootDisplayConfig(getInvalidDisplayId(), /*config*/ 0);
 
     EXPECT_FALSE(status.isOk());
@@ -501,6 +506,10 @@
 }
 
 TEST_P(GraphicsComposerAidlTest, SetBootDisplayConfig_BadConfig) {
+    if (!hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
+        GTEST_SUCCEED() << "Boot Display Config not supported";
+        return;
+    }
     for (VtsDisplay& display : mDisplays) {
         int32_t constexpr kInvalidConfigId = IComposerClient::INVALID_CONFIGURATION;
         const auto& status =
@@ -512,6 +521,10 @@
 }
 
 TEST_P(GraphicsComposerAidlTest, SetBootDisplayConfig) {
+    if (!hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
+        GTEST_SUCCEED() << "Boot Display Config not supported";
+        return;
+    }
     const auto& [status, configs] = mComposerClient->getDisplayConfigs(getPrimaryDisplayId());
     EXPECT_TRUE(status.isOk());
     for (const auto& config : configs) {
@@ -520,6 +533,10 @@
 }
 
 TEST_P(GraphicsComposerAidlTest, ClearBootDisplayConfig_BadDisplay) {
+    if (!hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
+        GTEST_SUCCEED() << "Boot Display Config not supported";
+        return;
+    }
     const auto& status = mComposerClient->clearBootDisplayConfig(getInvalidDisplayId());
 
     EXPECT_FALSE(status.isOk());
@@ -527,10 +544,18 @@
 }
 
 TEST_P(GraphicsComposerAidlTest, ClearBootDisplayConfig) {
+    if (!hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
+        GTEST_SUCCEED() << "Boot Display Config not supported";
+        return;
+    }
     EXPECT_TRUE(mComposerClient->clearBootDisplayConfig(getPrimaryDisplayId()).isOk());
 }
 
 TEST_P(GraphicsComposerAidlTest, GetPreferredBootDisplayConfig_BadDisplay) {
+    if (!hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
+        GTEST_SUCCEED() << "Boot Display Config not supported";
+        return;
+    }
     const auto& [status, _] = mComposerClient->getPreferredBootDisplayConfig(getInvalidDisplayId());
 
     EXPECT_FALSE(status.isOk());
@@ -538,6 +563,10 @@
 }
 
 TEST_P(GraphicsComposerAidlTest, GetPreferredBootDisplayConfig) {
+    if (!hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
+        GTEST_SUCCEED() << "Boot Display Config not supported";
+        return;
+    }
     const auto& [status, preferredDisplayConfig] =
             mComposerClient->getPreferredBootDisplayConfig(getPrimaryDisplayId());
     EXPECT_TRUE(status.isOk());
@@ -548,6 +577,26 @@
     EXPECT_NE(configs.end(), std::find(configs.begin(), configs.end(), preferredDisplayConfig));
 }
 
+TEST_P(GraphicsComposerAidlTest, BootDisplayConfig_Unsupported) {
+    if (!hasCapability(Capability::BOOT_DISPLAY_CONFIG)) {
+        const auto& [configStatus, config] =
+                mComposerClient->getActiveConfig(getPrimaryDisplayId());
+        EXPECT_TRUE(configStatus.isOk());
+
+        auto status = mComposerClient->setBootDisplayConfig(getPrimaryDisplayId(), config);
+        EXPECT_FALSE(status.isOk());
+        EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, status.getServiceSpecificError());
+
+        status = mComposerClient->getPreferredBootDisplayConfig(getPrimaryDisplayId()).first;
+        EXPECT_FALSE(status.isOk());
+        EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, status.getServiceSpecificError());
+
+        status = mComposerClient->clearBootDisplayConfig(getPrimaryDisplayId());
+        EXPECT_FALSE(status.isOk());
+        EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, status.getServiceSpecificError());
+    }
+}
+
 TEST_P(GraphicsComposerAidlTest, SetAutoLowLatencyMode_BadDisplay) {
     auto status = mComposerClient->setAutoLowLatencyMode(getInvalidDisplayId(), /*isEnabled*/ true);
     EXPECT_FALSE(status.isOk());
@@ -1035,11 +1084,10 @@
         }
     }
 
-    sp<GraphicBuffer> allocate() {
+    sp<GraphicBuffer> allocate(::android::PixelFormat pixelFormat) {
         return sp<GraphicBuffer>::make(
                 static_cast<uint32_t>(getPrimaryDisplay().getDisplayWidth()),
-                static_cast<uint32_t>(getPrimaryDisplay().getDisplayHeight()),
-                ::android::PIXEL_FORMAT_RGBA_8888,
+                static_cast<uint32_t>(getPrimaryDisplay().getDisplayHeight()), pixelFormat,
                 /*layerCount*/ 1U,
                 (static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
                  static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
@@ -1065,7 +1113,7 @@
                 mComposerClient->createLayer(display.getDisplayId(), kBufferSlotCount);
         EXPECT_TRUE(status.isOk());
         {
-            const auto buffer = allocate();
+            const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
             ASSERT_NE(nullptr, buffer);
             ASSERT_EQ(::android::OK, buffer->initCheck());
             ASSERT_NE(nullptr, buffer->handle);
@@ -1086,7 +1134,7 @@
         }
 
         {
-            const auto buffer = allocate();
+            const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
             ASSERT_NE(nullptr, buffer->handle);
 
             mWriter.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, buffer->handle,
@@ -1236,8 +1284,8 @@
 
         const auto vsyncPeriod = getVsyncPeriod();
 
-        const auto buffer1 = allocate();
-        const auto buffer2 = allocate();
+        const auto buffer1 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+        const auto buffer2 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
         ASSERT_NE(nullptr, buffer1);
         ASSERT_NE(nullptr, buffer2);
 
@@ -1391,7 +1439,7 @@
             kBufferSlotCount);
     EXPECT_TRUE(displayStatus.isOk());
 
-    const auto buffer = allocate();
+    const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
     const auto handle = buffer->handle;
     mWriter.setOutputBuffer(display.display, /*slot*/ 0, handle, /*releaseFence*/ -1);
     execute();
@@ -1435,7 +1483,7 @@
         EXPECT_TRUE(mComposerClient->setColorMode(getPrimaryDisplayId(), ColorMode::NATIVE, intent)
                             .isOk());
 
-        const auto buffer = allocate();
+        const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
         const auto handle = buffer->handle;
         ASSERT_NE(nullptr, handle);
 
@@ -1463,7 +1511,7 @@
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
 
-        const auto buffer2 = allocate();
+        const auto buffer2 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
         const auto handle2 = buffer2->handle;
         ASSERT_NE(nullptr, handle2);
         mWriter.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle2,
@@ -1480,7 +1528,7 @@
             mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
     EXPECT_TRUE(layerStatus.isOk());
 
-    const auto buffer = allocate();
+    const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
     const auto handle = buffer->handle;
     ASSERT_NE(nullptr, handle);
 
@@ -1513,7 +1561,7 @@
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerBuffer) {
-    const auto buffer = allocate();
+    const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
     const auto handle = buffer->handle;
     ASSERT_NE(nullptr, handle);
 
@@ -1619,6 +1667,47 @@
     execute();
 }
 
+TEST_P(GraphicsComposerAidlCommandTest, DisplayDecoration) {
+    for (VtsDisplay& display : mDisplays) {
+        const auto [layerStatus, layer] =
+                mComposerClient->createLayer(display.getDisplayId(), kBufferSlotCount);
+        EXPECT_TRUE(layerStatus.isOk());
+
+        const auto [error, support] =
+                mComposerClient->getDisplayDecorationSupport(display.getDisplayId());
+
+        const auto format = (error.isOk() && support) ? support->format
+                        : aidl::android::hardware::graphics::common::PixelFormat::RGBA_8888;
+        const auto decorBuffer = allocate(static_cast<::android::PixelFormat>(format));
+        ASSERT_NE(nullptr, decorBuffer);
+        if (::android::OK != decorBuffer->initCheck()) {
+            if (support) {
+                FAIL() << "Device advertised display decoration support with format  "
+                       << aidl::android::hardware::graphics::common::toString(format)
+                       << " but failed to allocate it!";
+            } else {
+                FAIL() << "Device advertised NO display decoration support, but it should "
+                       << "still be able to allocate "
+                       << aidl::android::hardware::graphics::common::toString(format);
+            }
+        }
+
+        mWriter.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, decorBuffer->handle,
+                               /*acquireFence*/ -1);
+        mWriter.setLayerCompositionType(display.getDisplayId(), layer,
+                                        Composition::DISPLAY_DECORATION);
+        mWriter.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
+        execute();
+        if (support) {
+            ASSERT_TRUE(mReader.takeErrors().empty());
+        } else {
+            const auto errors = mReader.takeErrors();
+            ASSERT_EQ(1, errors.size());
+            EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, errors[0].errorCode);
+        }
+    }
+}
+
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerDataspace) {
     const auto& [layerStatus, layer] =
             mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
@@ -1657,7 +1746,7 @@
         return;
     }
 
-    const auto buffer = allocate();
+    const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
     const auto handle = buffer->handle;
     ASSERT_NE(nullptr, handle);
 
@@ -1798,26 +1887,37 @@
     EXPECT_TRUE(mComposerClient->destroyLayer(getPrimaryDisplayId(), layer).isOk());
 }
 
-TEST_P(GraphicsComposerAidlCommandTest, SetLayerWhitePointNits) {
+TEST_P(GraphicsComposerAidlCommandTest, setLayerBrightness) {
     const auto& [layerStatus, layer] =
             mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
-    EXPECT_TRUE(layerStatus.isOk());
 
-    mWriter.setLayerWhitePointNits(getPrimaryDisplayId(), layer, /*whitePointNits*/ 200.f);
+    mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, 0.2f);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerWhitePointNits(getPrimaryDisplayId(), layer, /*whitePointNits*/ 1000.f);
+    mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, 1.f);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerWhitePointNits(getPrimaryDisplayId(), layer, /*whitePointNits*/ 0.f);
+    mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, 0.f);
     execute();
     ASSERT_TRUE(mReader.takeErrors().empty());
 
-    mWriter.setLayerWhitePointNits(getPrimaryDisplayId(), layer, /*whitePointNits*/ -1.f);
+    mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, -1.f);
     execute();
-    ASSERT_TRUE(mReader.takeErrors().empty());
+    {
+        const auto errors = mReader.takeErrors();
+        ASSERT_EQ(1, errors.size());
+        EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, errors[0].errorCode);
+    }
+
+    mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, std::nanf(""));
+    execute();
+    {
+        const auto errors = mReader.takeErrors();
+        ASSERT_EQ(1, errors.size());
+        EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, errors[0].errorCode);
+    }
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, SetActiveConfigWithConstraints) {
@@ -1971,7 +2071,7 @@
     EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::ON).isOk());
     EXPECT_TRUE(mComposerClient->setIdleTimerEnabled(getPrimaryDisplayId(), /*timeout*/ 0).isOk());
 
-    const auto buffer = allocate();
+    const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
     ASSERT_NE(nullptr, buffer->handle);
 
     const auto layer = createOnScreenLayer();
diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
index 5b2a94e..901f0e3 100644
--- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
@@ -303,6 +303,14 @@
     return supported;
 }
 
+bool Gralloc::isSupportedNoFailure(const IMapper::BufferDescriptorInfo& descriptorInfo) {
+    bool supported = false;
+    mMapper->isSupported(descriptorInfo, [&](const auto& tmpError, const auto& tmpSupported) {
+        supported = tmpSupported && tmpError == Error::NONE;
+    });
+    return supported;
+}
+
 Error Gralloc::get(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType,
                    hidl_vec<uint8_t>* outVec) {
     Error err;
diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
index 22a935f..c5406c9 100644
--- a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
+++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
@@ -111,6 +111,10 @@
 
     bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo);
 
+    // A version of isSupported that simply treats failure as no support, so it
+    // does not fail the test.
+    bool isSupportedNoFailure(const IMapper::BufferDescriptorInfo& descriptorInfo);
+
     Error get(const native_handle_t* bufferHandle, const IMapper::MetadataType& metadataType,
               hidl_vec<uint8_t>* outVec);
 
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 5e012f6..463b565 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -1220,7 +1220,7 @@
             aidl::android::hardware::graphics::common::PixelFormat::R_8);
     bool supported = false;
 
-    ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
+    supported = mGralloc->isSupportedNoFailure(info);
 
     if (!supported) {
         GTEST_SUCCEED() << "R_8 is optional; unsupported so skipping allocation test";
diff --git a/health/2.0/vts/functional/Android.bp b/health/2.0/vts/functional/Android.bp
index 0fcac19..597fb50 100644
--- a/health/2.0/vts/functional/Android.bp
+++ b/health/2.0/vts/functional/Android.bp
@@ -26,6 +26,7 @@
 cc_test {
     name: "VtsHalHealthV2_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: ["VtsHalHealthV2_0TargetTest.cpp"],
     srcs: ["VtsHalHealthV2_0TargetTest.cpp"],
     static_libs: [
         "libgflags",
diff --git a/health/aidl/default/Health.cpp b/health/aidl/default/Health.cpp
index e1d1982..d41d01a 100644
--- a/health/aidl/default/Health.cpp
+++ b/health/aidl/default/Health.cpp
@@ -130,12 +130,7 @@
 ndk::ScopedAStatus Health::getHealthInfo(HealthInfo* out) {
     battery_monitor_.updateValues();
 
-    // TODO(b/177269435): BatteryMonitor should store AIDL HealthInfo instead.
-    auto health_info_2_1 = battery_monitor_.getHealthInfo_2_1();
-    if (!::android::h2a::translate(health_info_2_1, out)) {
-        return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
-                IHealth::STATUS_UNKNOWN, "Cannot translate HIDL HealthInfo to AIDL");
-    }
+    *out = battery_monitor_.getHealthInfo();
 
     // Fill in storage infos; these aren't retrieved by BatteryMonitor.
     if (auto res = getStorageInfo(&out->storageInfos); !res.isOk()) {
diff --git a/health/aidl/vts/functional/Android.bp b/health/aidl/vts/functional/Android.bp
index d315c60..f9da79f 100644
--- a/health/aidl/vts/functional/Android.bp
+++ b/health/aidl/vts/functional/Android.bp
@@ -29,6 +29,9 @@
         "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
     ],
+    tidy_timeout_srcs: [
+        "VtsHalHealthTargetTest.cpp",
+    ],
     srcs: [
         "VtsHalHealthTargetTest.cpp",
     ],
diff --git a/health/utils/libhealthloop/HealthLoop.cpp b/health/utils/libhealthloop/HealthLoop.cpp
index 3f4b5bc..4190769 100644
--- a/health/utils/libhealthloop/HealthLoop.cpp
+++ b/health/utils/libhealthloop/HealthLoop.cpp
@@ -40,8 +40,6 @@
 using namespace android;
 using namespace std::chrono_literals;
 
-#define POWER_SUPPLY_SUBSYSTEM "power_supply"
-
 namespace android {
 namespace hardware {
 namespace health {
@@ -143,7 +141,7 @@
     cp = msg;
 
     while (*cp) {
-        if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
+        if (!strcmp(cp, "SUBSYSTEM=power_supply")) {
             ScheduleBatteryUpdate();
             break;
         }
diff --git a/health/utils/libhealthshim/Android.bp b/health/utils/libhealthshim/Android.bp
index 42e4ea7..3a1415f 100644
--- a/health/utils/libhealthshim/Android.bp
+++ b/health/utils/libhealthshim/Android.bp
@@ -70,6 +70,9 @@
         "libhealthshim",
         "libgmock",
     ],
+    tidy_timeout_srcs: [
+        "test.cpp",
+    ],
     srcs: [
         "test.cpp",
     ],
diff --git a/identity/support/Android.bp b/identity/support/Android.bp
index db1a945..4e3d1f7 100644
--- a/identity/support/Android.bp
+++ b/identity/support/Android.bp
@@ -86,6 +86,9 @@
 
 cc_test {
     name: "cppbor_test",
+    tidy_timeout_srcs: [
+        "tests/cppbor_test.cpp",
+    ],
     srcs: [
         "tests/cppbor_test.cpp",
     ],
@@ -101,6 +104,9 @@
 
 cc_test_host {
     name: "cppbor_host_test",
+    tidy_timeout_srcs: [
+        "tests/cppbor_test.cpp",
+    ],
     srcs: [
         "tests/cppbor_test.cpp",
     ],
diff --git a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
index 82746d6..952b69a 100644
--- a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
+++ b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
@@ -407,6 +407,10 @@
 // may be smaller than |maxChunkSize|.
 vector<vector<uint8_t>> chunkVector(const vector<uint8_t>& content, size_t maxChunkSize);
 
+// Extract the issuer subject name from the leaf cert in the given chain,
+// returning it as DER-encoded bytes.
+optional<vector<uint8_t>> extractDerSubjectFromCertificate(const vector<uint8_t>& certificate);
+
 }  // namespace support
 }  // namespace identity
 }  // namespace hardware
diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp
index 36ecdb0..4c2f186 100644
--- a/identity/support/src/IdentityCredentialSupport.cpp
+++ b/identity/support/src/IdentityCredentialSupport.cpp
@@ -209,38 +209,6 @@
     return keyPair;
 }
 
-// Extract the issuer subject name from the leaf cert in the given chain,
-// returning it as DER-encoded bytes.
-optional<vector<uint8_t>> extractDerSubjectFromCertificate(const vector<uint8_t>& certificate) {
-    const uint8_t* input = certificate.data();
-    X509_Ptr cert(d2i_X509(/*cert=*/nullptr, &input, certificate.size()));
-    if (!cert) {
-        LOG(ERROR) << "Failed to parse certificate";
-        return std::nullopt;
-    }
-
-    X509_NAME* subject = X509_get_subject_name(cert.get());
-    if (!subject) {
-        LOG(ERROR) << "Failed to retrieve subject name";
-        return std::nullopt;
-    }
-
-    int encodedSubjectLength = i2d_X509_NAME(subject, /*out=*/nullptr);
-    if (encodedSubjectLength < 0) {
-        LOG(ERROR) << "Error obtaining encoded subject name length";
-        return std::nullopt;
-    }
-
-    vector<uint8_t> encodedSubject(encodedSubjectLength);
-    uint8_t* out = encodedSubject.data();
-    if (encodedSubjectLength != i2d_X509_NAME(subject, &out)) {
-        LOG(ERROR) << "Error encoding subject name";
-        return std::nullopt;
-    }
-
-    return encodedSubject;
-}
-
 // Generates the attestation certificate with the parameters passed in.  Note
 // that the passed in |activeTimeMilliSeconds| |expireTimeMilliSeconds| are in
 // milli seconds since epoch.  We are setting them to milliseconds due to
@@ -900,7 +868,7 @@
     }
 
     optional<vector<uint8_t>> derIssuerSubject =
-            extractDerSubjectFromCertificate(attestationKeyCert);
+            support::extractDerSubjectFromCertificate(attestationKeyCert);
     if (!derIssuerSubject) {
         LOG(ERROR) << "Error error extracting issuer name from the given certificate chain";
         return std::nullopt;
@@ -2325,6 +2293,36 @@
     return testHardwareBoundKey;
 }
 
+optional<vector<uint8_t>> extractDerSubjectFromCertificate(const vector<uint8_t>& certificate) {
+    const uint8_t* input = certificate.data();
+    X509_Ptr cert(d2i_X509(/*cert=*/nullptr, &input, certificate.size()));
+    if (!cert) {
+        LOG(ERROR) << "Failed to parse certificate";
+        return std::nullopt;
+    }
+
+    X509_NAME* subject = X509_get_subject_name(cert.get());
+    if (!subject) {
+        LOG(ERROR) << "Failed to retrieve subject name";
+        return std::nullopt;
+    }
+
+    int encodedSubjectLength = i2d_X509_NAME(subject, /*out=*/nullptr);
+    if (encodedSubjectLength < 0) {
+        LOG(ERROR) << "Error obtaining encoded subject name length";
+        return std::nullopt;
+    }
+
+    vector<uint8_t> encodedSubject(encodedSubjectLength);
+    uint8_t* out = encodedSubject.data();
+    if (encodedSubjectLength != i2d_X509_NAME(subject, &out)) {
+        LOG(ERROR) << "Error encoding subject name";
+        return std::nullopt;
+    }
+
+    return encodedSubject;
+}
+
 }  // namespace support
 }  // namespace identity
 }  // namespace hardware
diff --git a/keymaster/3.0/vts/OWNERS b/keymaster/3.0/vts/OWNERS
index 376c12b..846bb84 100644
--- a/keymaster/3.0/vts/OWNERS
+++ b/keymaster/3.0/vts/OWNERS
@@ -1,3 +1,4 @@
+drysdale@google.com
 jdanis@google.com
 swillden@google.com
 yim@google.com
diff --git a/keymaster/3.0/vts/functional/Android.bp b/keymaster/3.0/vts/functional/Android.bp
index 39bec3f..fde32a7 100644
--- a/keymaster/3.0/vts/functional/Android.bp
+++ b/keymaster/3.0/vts/functional/Android.bp
@@ -26,6 +26,9 @@
 cc_test {
     name: "VtsHalKeymasterV3_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: [
+        "keymaster_hidl_hal_test.cpp",
+    ],
     srcs: [
         "authorization_set.cpp",
         "attestation_record.cpp",
diff --git a/keymaster/4.0/vts/OWNERS b/keymaster/4.0/vts/OWNERS
index abfb2e0..0d6fa6c 100644
--- a/keymaster/4.0/vts/OWNERS
+++ b/keymaster/4.0/vts/OWNERS
@@ -1,3 +1,4 @@
+drysdale@google.com
 jbires@google.com
 jdanis@google.com
 swillden@google.com
diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp
index 8e5a0ff..f9a02ba 100644
--- a/keymaster/4.0/vts/functional/Android.bp
+++ b/keymaster/4.0/vts/functional/Android.bp
@@ -26,6 +26,9 @@
 cc_test {
     name: "VtsHalKeymasterV4_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: [
+        "keymaster_hidl_hal_test.cpp",
+    ],
     srcs: [
         "HmacKeySharingTest.cpp",
         "VerificationTokenTest.cpp",
@@ -50,6 +53,9 @@
 cc_test_library {
     name: "libkeymaster4vtstest",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: [
+        "KeymasterHidlTest.cpp",
+    ],
     srcs: [
         "KeymasterHidlTest.cpp",
     ],
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
index d0ad433..315a4bd 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
@@ -443,6 +443,101 @@
         AuthorizationSetBuilder().Digest(digest).Authorization(TAG_MAC_LENGTH, mac_length));
 }
 
+void KeymasterHidlTest::CheckAesIncrementalEncryptOperation(BlockMode block_mode,
+                                                            int message_size) {
+    auto builder = AuthorizationSetBuilder()
+                           .Authorization(TAG_NO_AUTH_REQUIRED)
+                           .AesEncryptionKey(128)
+                           .BlockMode(block_mode)
+                           .Padding(PaddingMode::NONE);
+    if (block_mode == BlockMode::GCM) {
+        builder.Authorization(TAG_MIN_MAC_LENGTH, 128);
+    }
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(builder));
+
+    for (int increment = 1; increment <= message_size; ++increment) {
+        string message(message_size, 'a');
+        auto params = AuthorizationSetBuilder()
+                              .BlockMode(block_mode)
+                              .Padding(PaddingMode::NONE)
+                              .Authorization(TAG_MAC_LENGTH, 128) /* for GCM */;
+
+        AuthorizationSet output_params;
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
+
+        string ciphertext;
+        size_t input_consumed;
+        string to_send;
+        for (size_t i = 0; i < message.size(); i += increment) {
+            to_send.append(message.substr(i, increment));
+            EXPECT_EQ(ErrorCode::OK, Update(to_send, &ciphertext, &input_consumed));
+            EXPECT_EQ(to_send.length(), input_consumed);
+            to_send = to_send.substr(input_consumed);
+            EXPECT_EQ(0U, to_send.length());
+
+            switch (block_mode) {
+                case BlockMode::ECB:
+                case BlockMode::CBC:
+                    // Implementations must take as many blocks as possible, leaving less than
+                    // a block.
+                    EXPECT_LE(to_send.length(), 16U);
+                    break;
+                case BlockMode::GCM:
+                case BlockMode::CTR:
+                    // Implementations must always take all the data.
+                    EXPECT_EQ(0U, to_send.length());
+                    break;
+            }
+        }
+        EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext)) << "Error sending " << to_send;
+
+        switch (block_mode) {
+            case BlockMode::GCM:
+                EXPECT_EQ(message.size() + 16, ciphertext.size());
+                break;
+            case BlockMode::CTR:
+                EXPECT_EQ(message.size(), ciphertext.size());
+                break;
+            case BlockMode::CBC:
+            case BlockMode::ECB:
+                EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size());
+                break;
+        }
+
+        auto iv = output_params.GetTagValue(TAG_NONCE);
+        switch (block_mode) {
+            case BlockMode::CBC:
+            case BlockMode::GCM:
+            case BlockMode::CTR:
+                ASSERT_TRUE(iv.isOk()) << "No IV for block mode " << block_mode;
+                EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv.value().size());
+                params.push_back(TAG_NONCE, iv.value());
+                break;
+
+            case BlockMode::ECB:
+                EXPECT_FALSE(iv.isOk()) << "ECB mode should not generate IV";
+                break;
+        }
+
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params))
+                << "Decrypt begin() failed for block mode " << block_mode;
+
+        string plaintext;
+        for (size_t i = 0; i < ciphertext.size(); i += increment) {
+            to_send.append(ciphertext.substr(i, increment));
+            EXPECT_EQ(ErrorCode::OK, Update(to_send, &plaintext, &input_consumed));
+            to_send = to_send.substr(input_consumed);
+        }
+        ErrorCode error = Finish(to_send, &plaintext);
+        ASSERT_EQ(ErrorCode::OK, error) << "Decryption failed for block mode " << block_mode
+                                        << " and increment " << increment;
+        if (error == ErrorCode::OK) {
+            ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode " << block_mode
+                                          << " and increment " << increment;
+        }
+    }
+}
+
 void KeymasterHidlTest::CheckHmacTestVector(const string& key, const string& message, Digest digest,
                                             const string& expected_mac) {
     SCOPED_TRACE("CheckHmacTestVector");
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
index 2ca7ea7..ad30aa7 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
@@ -166,6 +166,8 @@
 
     string MacMessage(const string& message, Digest digest, size_t mac_length);
 
+    void CheckAesIncrementalEncryptOperation(BlockMode block_mode, int message_size);
+
     void CheckHmacTestVector(const string& key, const string& message, Digest digest,
                              const string& expected_mac);
 
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 6412f3a..22aa0f9 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -2932,105 +2932,39 @@
 }
 
 /*
- * EncryptionOperationsTest.AesIncremental
+ * EncryptionOperationsTest.AesEcbIncremental
  *
- * Verifies that AES works, all modes, when provided data in various size increments.
+ * Verifies that AES works for ECB block mode, when provided data in various size increments.
  */
-TEST_P(EncryptionOperationsTest, AesIncremental) {
-    auto block_modes = {
-        BlockMode::ECB, BlockMode::CBC, BlockMode::CTR, BlockMode::GCM,
-    };
+TEST_P(EncryptionOperationsTest, AesEcbIncremental) {
+    CheckAesIncrementalEncryptOperation(BlockMode::ECB, 240);
+}
 
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                             .Authorization(TAG_NO_AUTH_REQUIRED)
-                                             .AesEncryptionKey(128)
-                                             .BlockMode(block_modes)
-                                             .Padding(PaddingMode::NONE)
-                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+/*
+ * EncryptionOperationsTest.AesCbcIncremental
+ *
+ * Verifies that AES works for CBC block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesCbcIncremental) {
+    CheckAesIncrementalEncryptOperation(BlockMode::CBC, 240);
+}
 
-    for (int increment = 1; increment <= 240; ++increment) {
-        for (auto block_mode : block_modes) {
-            string message(240, 'a');
-            auto params = AuthorizationSetBuilder()
-                              .BlockMode(block_mode)
-                              .Padding(PaddingMode::NONE)
-                              .Authorization(TAG_MAC_LENGTH, 128) /* for GCM */;
+/*
+ * EncryptionOperationsTest.AesCtrIncremental
+ *
+ * Verifies that AES works for CTR block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesCtrIncremental) {
+    CheckAesIncrementalEncryptOperation(BlockMode::CTR, 240);
+}
 
-            AuthorizationSet output_params;
-            EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
-
-            string ciphertext;
-            size_t input_consumed;
-            string to_send;
-            for (size_t i = 0; i < message.size(); i += increment) {
-                to_send.append(message.substr(i, increment));
-                EXPECT_EQ(ErrorCode::OK, Update(to_send, &ciphertext, &input_consumed));
-                EXPECT_EQ(to_send.length(), input_consumed);
-                to_send = to_send.substr(input_consumed);
-                EXPECT_EQ(0U, to_send.length());
-
-                switch (block_mode) {
-                    case BlockMode::ECB:
-                    case BlockMode::CBC:
-                        // Implementations must take as many blocks as possible, leaving less than
-                        // a block.
-                        EXPECT_LE(to_send.length(), 16U);
-                        break;
-                    case BlockMode::GCM:
-                    case BlockMode::CTR:
-                        // Implementations must always take all the data.
-                        EXPECT_EQ(0U, to_send.length());
-                        break;
-                }
-            }
-            EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext)) << "Error sending " << to_send;
-
-            switch (block_mode) {
-                case BlockMode::GCM:
-                    EXPECT_EQ(message.size() + 16, ciphertext.size());
-                    break;
-                case BlockMode::CTR:
-                    EXPECT_EQ(message.size(), ciphertext.size());
-                    break;
-                case BlockMode::CBC:
-                case BlockMode::ECB:
-                    EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size());
-                    break;
-            }
-
-            auto iv = output_params.GetTagValue(TAG_NONCE);
-            switch (block_mode) {
-                case BlockMode::CBC:
-                case BlockMode::GCM:
-                case BlockMode::CTR:
-                    ASSERT_TRUE(iv.isOk()) << "No IV for block mode " << block_mode;
-                    EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv.value().size());
-                    params.push_back(TAG_NONCE, iv.value());
-                    break;
-
-                case BlockMode::ECB:
-                    EXPECT_FALSE(iv.isOk()) << "ECB mode should not generate IV";
-                    break;
-            }
-
-            EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params))
-                << "Decrypt begin() failed for block mode " << block_mode;
-
-            string plaintext;
-            for (size_t i = 0; i < ciphertext.size(); i += increment) {
-                to_send.append(ciphertext.substr(i, increment));
-                EXPECT_EQ(ErrorCode::OK, Update(to_send, &plaintext, &input_consumed));
-                to_send = to_send.substr(input_consumed);
-            }
-            ErrorCode error = Finish(to_send, &plaintext);
-            ASSERT_EQ(ErrorCode::OK, error) << "Decryption failed for block mode " << block_mode
-                                            << " and increment " << increment;
-            if (error == ErrorCode::OK) {
-                ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode "
-                                              << block_mode << " and increment " << increment;
-            }
-        }
-    }
+/*
+ * EncryptionOperationsTest.AesGcmIncremental
+ *
+ * Verifies that AES works for GCM block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmIncremental) {
+    CheckAesIncrementalEncryptOperation(BlockMode::GCM, 240);
 }
 
 struct AesCtrSp80038aTestVector {
diff --git a/keymaster/4.1/vts/OWNERS b/keymaster/4.1/vts/OWNERS
index 2b2ad2a..24ed042 100644
--- a/keymaster/4.1/vts/OWNERS
+++ b/keymaster/4.1/vts/OWNERS
@@ -1,3 +1,4 @@
+drysdale@google.com
 jbires@google.com
 jdanis@google.com
 swillden@google.com
diff --git a/light/aidl/vts/functional/Android.bp b/light/aidl/vts/functional/Android.bp
index c5a8562..16804ea 100644
--- a/light/aidl/vts/functional/Android.bp
+++ b/light/aidl/vts/functional/Android.bp
@@ -36,7 +36,7 @@
         "libbinder",
     ],
     static_libs: [
-        "android.hardware.light-V1-cpp",
+        "android.hardware.light-V2-cpp",
     ],
     test_suites: [
         "vts",
diff --git a/media/omx/1.0/vts/functional/component/Android.bp b/media/omx/1.0/vts/functional/component/Android.bp
index 9d4d092..7b8ec9d 100644
--- a/media/omx/1.0/vts/functional/component/Android.bp
+++ b/media/omx/1.0/vts/functional/component/Android.bp
@@ -26,6 +26,7 @@
 cc_test {
     name: "VtsHalMediaOmxV1_0TargetComponentTest",
     defaults: ["VtsHalMediaOmxV1_0Defaults"],
+    tidy_timeout_srcs: ["VtsHalMediaOmxV1_0TargetComponentTest.cpp"],
     srcs: ["VtsHalMediaOmxV1_0TargetComponentTest.cpp"],
     test_suites: [
         "vts",
diff --git a/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp b/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
index 8699de3..d9a6363 100644
--- a/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
+++ b/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
@@ -20,7 +20,9 @@
 #endif
 
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/strings.h>
+#include <android/api-level.h>
 
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <android/hardware/media/omx/1.0/IOmxNode.h>
@@ -371,6 +373,31 @@
     }
 }
 
+static int getFirstApiLevel() {
+    return android::base::GetIntProperty("ro.product.first_api_level", __ANDROID_API_T__);
+}
+
+// list components and roles.
+TEST_P(StoreHidlTest, OmxCodecAllowedTest) {
+    hidl_vec<IOmx::ComponentInfo> componentInfos = getComponentInfoList(omx);
+    for (IOmx::ComponentInfo info : componentInfos) {
+        for (std::string role : info.mRoles) {
+            if (role.find("video_decoder") != std::string::npos ||
+                role.find("video_encoder") != std::string::npos) {
+                ASSERT_LT(getFirstApiLevel(), __ANDROID_API_S__)
+                        << " Component: " << info.mName.c_str() << " Role: " << role.c_str()
+                        << " not allowed for devices launching with Android S and above";
+            }
+            if (role.find("audio_decoder") != std::string::npos ||
+                role.find("audio_encoder") != std::string::npos) {
+                ASSERT_LT(getFirstApiLevel(), __ANDROID_API_T__)
+                        << " Component: " << info.mName.c_str() << " Role: " << role.c_str()
+                        << " not allowed for devices launching with Android T and above";
+            }
+        }
+    }
+}
+
 // list components and roles.
 TEST_P(StoreHidlTest, ListNodes) {
     description("enumerate component and roles");
diff --git a/neuralnetworks/1.2/utils/Android.bp b/neuralnetworks/1.2/utils/Android.bp
index 4c5f065..e7d514f 100644
--- a/neuralnetworks/1.2/utils/Android.bp
+++ b/neuralnetworks/1.2/utils/Android.bp
@@ -45,21 +45,15 @@
             cflags: ["-DNN_DEBUGGABLE"],
         },
     },
-    target: {
-        host: {
-            cflags: [
-                "-D__INTRODUCED_IN(x)=",
-                "-D__assert(a,b,c)=",
-                // We want all the APIs to be available on the host.
-                "-D__ANDROID_API__=10000",
-            ],
-        },
-    },
 }
 
 cc_test {
     name: "neuralnetworks_utils_hal_1_2_test",
     host_supported: true,
+    tidy_timeout_srcs: [
+        "test/DeviceTest.cpp",
+        "test/PreparedModelTest.cpp",
+    ],
     srcs: ["test/*.cpp"],
     static_libs: [
         "android.hardware.neuralnetworks@1.0",
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index 52d51e2..2177924 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -44,6 +44,9 @@
 cc_test {
     name: "VtsHalNeuralnetworksV1_2TargetTest",
     defaults: ["neuralnetworks_vts_functional_defaults"],
+    tidy_timeout_srcs: [
+        "CompilationCachingTests.cpp",
+    ],
     srcs: [
         "BasicTests.cpp",
         "CompilationCachingTests.cpp",
diff --git a/neuralnetworks/1.3/utils/Android.bp b/neuralnetworks/1.3/utils/Android.bp
index c512dda..05413e6 100644
--- a/neuralnetworks/1.3/utils/Android.bp
+++ b/neuralnetworks/1.3/utils/Android.bp
@@ -42,21 +42,15 @@
         "neuralnetworks_utils_hal_1_1",
         "neuralnetworks_utils_hal_1_2",
     ],
-    target: {
-        host: {
-            cflags: [
-                "-D__INTRODUCED_IN(x)=",
-                "-D__assert(a,b,c)=",
-                // We want all the APIs to be available on the host.
-                "-D__ANDROID_API__=10000",
-            ],
-        },
-    },
 }
 
 cc_test {
     name: "neuralnetworks_utils_hal_1_3_test",
     host_supported: true,
+    tidy_timeout_srcs: [
+        "test/DeviceTest.cpp",
+        "test/PreparedModelTest.cpp",
+    ],
     srcs: ["test/*.cpp"],
     static_libs: [
         "android.hardware.neuralnetworks@1.0",
diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp
index 8951760..9fa0f0a 100644
--- a/neuralnetworks/1.3/vts/functional/Android.bp
+++ b/neuralnetworks/1.3/vts/functional/Android.bp
@@ -45,6 +45,10 @@
 cc_test {
     name: "VtsHalNeuralnetworksV1_3TargetTest",
     defaults: ["neuralnetworks_vts_functional_defaults"],
+    tidy_timeout_srcs: [
+        "CompilationCachingTests.cpp",
+        "MemoryDomainTests.cpp",
+    ],
     srcs: [
         "BasicTests.cpp",
         "CompilationCachingTests.cpp",
diff --git a/neuralnetworks/aidl/utils/Android.bp b/neuralnetworks/aidl/utils/Android.bp
index 9148eac..3258092 100644
--- a/neuralnetworks/aidl/utils/Android.bp
+++ b/neuralnetworks/aidl/utils/Android.bp
@@ -105,6 +105,10 @@
         "neuralnetworks_use_latest_utils_hal_aidl",
         "neuralnetworks_utils_defaults",
     ],
+    tidy_timeout_srcs: [
+        "test/DeviceTest.cpp",
+        "test/PreparedModelTest.cpp",
+    ],
     srcs: [
         "test/*.cpp",
     ],
@@ -123,14 +127,6 @@
         android: {
             shared_libs: ["libnativewindow"],
         },
-        host: {
-            cflags: [
-                "-D__INTRODUCED_IN(x)=",
-                "-D__assert(a,b,c)=",
-                // We want all the APIs to be available on the host.
-                "-D__ANDROID_API__=10000",
-            ],
-        },
     },
     cflags: [
         /* GMOCK defines functions for printing all MOCK_DEVICE arguments and
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Service.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Service.h
index cb6ff4b..f229165 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Service.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Service.h
@@ -25,7 +25,8 @@
 
 namespace aidl::android::hardware::neuralnetworks::utils {
 
-::android::nn::GeneralResult<::android::nn::SharedDevice> getDevice(const std::string& name);
+::android::nn::GeneralResult<::android::nn::SharedDevice> getDevice(
+        const std::string& name, ::android::nn::Version::Level maxFeatureLevelAllowed);
 
 }  // namespace aidl::android::hardware::neuralnetworks::utils
 
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
index beca38b..7ed5437 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
@@ -26,6 +26,8 @@
 #include <nnapi/Types.h>
 #include <nnapi/Validation.h>
 
+#include <type_traits>
+
 namespace aidl::android::hardware::neuralnetworks::utils {
 
 constexpr auto kDefaultPriority = Priority::MEDIUM;
@@ -80,6 +82,11 @@
     return convert(NN_TRY(nn::convert(nonCanonicalObject)));
 }
 
+template <typename Type>
+constexpr std::underlying_type_t<Type> underlyingType(Type value) {
+    return static_cast<std::underlying_type_t<Type>>(value);
+}
+
 nn::GeneralResult<Memory> clone(const Memory& memory);
 nn::GeneralResult<Request> clone(const Request& request);
 nn::GeneralResult<RequestMemoryPool> clone(const RequestMemoryPool& requestPool);
diff --git a/neuralnetworks/aidl/utils/src/Conversions.cpp b/neuralnetworks/aidl/utils/src/Conversions.cpp
index 83fda10..081e3d7 100644
--- a/neuralnetworks/aidl/utils/src/Conversions.cpp
+++ b/neuralnetworks/aidl/utils/src/Conversions.cpp
@@ -57,10 +57,6 @@
     while (UNLIKELY(value > std::numeric_limits<int32_t>::max())) return NN_ERROR()
 
 namespace {
-template <typename Type>
-constexpr std::underlying_type_t<Type> underlyingType(Type value) {
-    return static_cast<std::underlying_type_t<Type>>(value);
-}
 
 constexpr int64_t kNoTiming = -1;
 
@@ -70,6 +66,7 @@
 namespace {
 
 using ::aidl::android::hardware::common::NativeHandle;
+using ::aidl::android::hardware::neuralnetworks::utils::underlyingType;
 
 template <typename Input>
 using UnvalidatedConvertOutput =
@@ -404,7 +401,7 @@
 #endif  // __ANDROID__
         }
     }
-    return NN_ERROR() << "Unrecognized Memory::Tag: " << memory.getTag();
+    return NN_ERROR() << "Unrecognized Memory::Tag: " << underlyingType(memory.getTag());
 }
 
 GeneralResult<Timing> unvalidatedConvert(const aidl_hal::Timing& timing) {
diff --git a/neuralnetworks/aidl/utils/src/Service.cpp b/neuralnetworks/aidl/utils/src/Service.cpp
index e48593c..24fbb53 100644
--- a/neuralnetworks/aidl/utils/src/Service.cpp
+++ b/neuralnetworks/aidl/utils/src/Service.cpp
@@ -55,11 +55,12 @@
 
 }  // namespace
 
-nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& instanceName) {
+nn::GeneralResult<nn::SharedDevice> getDevice(
+        const std::string& instanceName, ::android::nn::Version::Level maxFeatureLevelAllowed) {
     auto fullName = std::string(IDevice::descriptor) + "/" + instanceName;
     hal::utils::ResilientDevice::Factory makeDevice =
-            [instanceName,
-             name = std::move(fullName)](bool blocking) -> nn::GeneralResult<nn::SharedDevice> {
+            [instanceName, name = std::move(fullName),
+             maxFeatureLevelAllowed](bool blocking) -> nn::GeneralResult<nn::SharedDevice> {
         std::add_pointer_t<AIBinder*(const char*)> getService;
         if (blocking) {
             if (__builtin_available(android __NNAPI_AIDL_MIN_ANDROID_API__, *)) {
@@ -79,7 +80,8 @@
                    << " returned nullptr";
         }
         ABinderProcess_startThreadPool();
-        const auto featureLevel = NN_TRY(getAidlServiceFeatureLevel(service.get()));
+        auto featureLevel = NN_TRY(getAidlServiceFeatureLevel(service.get()));
+        featureLevel.level = std::min(featureLevel.level, maxFeatureLevelAllowed);
         return Device::create(instanceName, std::move(service), featureLevel);
     };
 
diff --git a/neuralnetworks/aidl/utils/src/Utils.cpp b/neuralnetworks/aidl/utils/src/Utils.cpp
index 03407be..76a0b07 100644
--- a/neuralnetworks/aidl/utils/src/Utils.cpp
+++ b/neuralnetworks/aidl/utils/src/Utils.cpp
@@ -88,7 +88,7 @@
             return Memory::make<Memory::Tag::hardwareBuffer>(std::move(handle));
         }
     }
-    return (NN_ERROR() << "Unrecognized Memory::Tag: " << memory.getTag())
+    return (NN_ERROR() << "Unrecognized Memory::Tag: " << underlyingType(memory.getTag()))
             .
             operator nn::GeneralResult<Memory>();
 }
@@ -103,7 +103,7 @@
     }
     // Using explicit type conversion because std::variant inside the RequestMemoryPool confuses the
     // compiler.
-    return (NN_ERROR() << "Unrecognized request pool tag: " << requestPool.getTag())
+    return (NN_ERROR() << "Unrecognized request pool tag: " << underlyingType(requestPool.getTag()))
             .
             operator nn::GeneralResult<RequestMemoryPool>();
 }
diff --git a/neuralnetworks/aidl/vts/functional/Android.bp b/neuralnetworks/aidl/vts/functional/Android.bp
index 356cdb0..04b4a45 100644
--- a/neuralnetworks/aidl/vts/functional/Android.bp
+++ b/neuralnetworks/aidl/vts/functional/Android.bp
@@ -31,6 +31,10 @@
         "use_libaidlvintf_gtest_helper_static",
     ],
     host_supported: true,
+    tidy_timeout_srcs: [
+        "CompilationCachingTests.cpp",
+        "MemoryDomainTests.cpp",
+    ],
     srcs: [
         "BasicTests.cpp",
         "Callbacks.cpp",
diff --git a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Adapter.h b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Adapter.h
index 4c0b328..80ed41d 100644
--- a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Adapter.h
+++ b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Adapter.h
@@ -46,9 +46,6 @@
 /**
  * Adapt an NNAPI canonical interface object to a AIDL NN HAL interface object.
  *
- * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
- * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
- *
  * @param device NNAPI canonical IDevice interface object to be adapted.
  * @param executor Type-erased executor to handle executing tasks asynchronously.
  * @return AIDL NN HAL IDevice interface object.
@@ -58,9 +55,6 @@
 /**
  * Adapt an NNAPI canonical interface object to a AIDL NN HAL interface object.
  *
- * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
- * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
- *
  * This function uses a default executor, which will execute tasks from a detached thread.
  *
  * @param device NNAPI canonical IDevice interface object to be adapted.
diff --git a/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Adapter.h b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Adapter.h
index 6fba4ab..3bd93e0 100644
--- a/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Adapter.h
+++ b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Adapter.h
@@ -46,9 +46,6 @@
 /**
  * Adapt an NNAPI canonical interface object to a HIDL NN HAL interface object.
  *
- * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
- * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
- *
  * @param device NNAPI canonical IDevice interface object to be adapted.
  * @param executor Type-erased executor to handle executing tasks asynchronously.
  * @return HIDL NN HAL IDevice interface object.
@@ -58,9 +55,6 @@
 /**
  * Adapt an NNAPI canonical interface object to a HIDL NN HAL interface object.
  *
- * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
- * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
- *
  * This function uses a default executor, which will execute tasks from a detached thread.
  *
  * @param device NNAPI canonical IDevice interface object to be adapted.
diff --git a/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/PreparedModel.h b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/PreparedModel.h
index 9482b0d..01cd4bc 100644
--- a/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/PreparedModel.h
+++ b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/PreparedModel.h
@@ -39,7 +39,7 @@
 // Class that adapts nn::IPreparedModel to V1_3::IPreparedModel.
 class PreparedModel final : public V1_3::IPreparedModel {
   public:
-    PreparedModel(nn::SharedPreparedModel preparedModel, Executor executor);
+    explicit PreparedModel(nn::SharedPreparedModel preparedModel);
 
     Return<V1_0::ErrorStatus> execute(const V1_0::Request& request,
                                       const sp<V1_0::IExecutionCallback>& callback) override;
@@ -70,7 +70,6 @@
 
   private:
     const nn::SharedPreparedModel kPreparedModel;
-    const Executor kExecutor;
 };
 
 }  // namespace android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/adapter/hidl/src/Device.cpp b/neuralnetworks/utils/adapter/hidl/src/Device.cpp
index 0f44638..305a1b4 100644
--- a/neuralnetworks/utils/adapter/hidl/src/Device.cpp
+++ b/neuralnetworks/utils/adapter/hidl/src/Device.cpp
@@ -62,11 +62,11 @@
 
 using PrepareModelResult = nn::GeneralResult<nn::SharedPreparedModel>;
 
-sp<PreparedModel> adaptPreparedModel(nn::SharedPreparedModel preparedModel, Executor executor) {
+sp<PreparedModel> adaptPreparedModel(nn::SharedPreparedModel preparedModel) {
     if (preparedModel == nullptr) {
         return nullptr;
     }
-    return sp<PreparedModel>::make(std::move(preparedModel), std::move(executor));
+    return sp<PreparedModel>::make(std::move(preparedModel));
 }
 
 void notify(V1_0::IPreparedModelCallback* callback, nn::ErrorStatus status,
@@ -105,14 +105,14 @@
 }
 
 template <typename CallbackType>
-void notify(CallbackType* callback, PrepareModelResult result, Executor executor) {
+void notify(CallbackType* callback, PrepareModelResult result) {
     if (!result.has_value()) {
         const auto [message, status] = std::move(result).error();
         LOG(ERROR) << message;
         notify(callback, status, nullptr);
     } else {
         auto preparedModel = std::move(result).value();
-        auto hidlPreparedModel = adaptPreparedModel(std::move(preparedModel), std::move(executor));
+        auto hidlPreparedModel = adaptPreparedModel(std::move(preparedModel));
         notify(callback, nn::ErrorStatus::NONE, std::move(hidlPreparedModel));
     }
 }
@@ -133,10 +133,10 @@
 
     auto nnModel = NN_TRY(convertInput(model));
 
-    Task task = [device, nnModel = std::move(nnModel), executor, callback] {
+    Task task = [device, nnModel = std::move(nnModel), callback] {
         auto result = device->prepareModel(nnModel, nn::ExecutionPreference::DEFAULT,
                                            nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
-        notify(callback.get(), std::move(result), executor);
+        notify(callback.get(), std::move(result));
     };
     executor(std::move(task), {});
 
@@ -154,10 +154,10 @@
     auto nnModel = NN_TRY(convertInput(model));
     const auto nnPreference = NN_TRY(convertInput(preference));
 
-    Task task = [device, nnModel = std::move(nnModel), nnPreference, executor, callback] {
+    Task task = [device, nnModel = std::move(nnModel), nnPreference, callback] {
         auto result = device->prepareModel(nnModel, nnPreference, nn::Priority::DEFAULT, {}, {}, {},
                                            {}, {}, {});
-        notify(callback.get(), std::move(result), executor);
+        notify(callback.get(), std::move(result));
     };
     executor(std::move(task), {});
 
@@ -183,10 +183,10 @@
 
     Task task = [device, nnModel = std::move(nnModel), nnPreference,
                  nnModelCache = std::move(nnModelCache), nnDataCache = std::move(nnDataCache),
-                 nnToken, executor, callback] {
+                 nnToken, callback] {
         auto result = device->prepareModel(nnModel, nnPreference, nn::Priority::DEFAULT, {},
                                            nnModelCache, nnDataCache, nnToken, {}, {});
-        notify(callback.get(), std::move(result), executor);
+        notify(callback.get(), std::move(result));
     };
     executor(std::move(task), {});
 
@@ -213,10 +213,10 @@
 
     Task task = [device, nnModel = std::move(nnModel), nnPreference, nnPriority, nnDeadline,
                  nnModelCache = std::move(nnModelCache), nnDataCache = std::move(nnDataCache),
-                 nnToken, executor, callback] {
+                 nnToken, callback] {
         auto result = device->prepareModel(nnModel, nnPreference, nnPriority, nnDeadline,
                                            nnModelCache, nnDataCache, nnToken, {}, {});
-        notify(callback.get(), std::move(result), executor);
+        notify(callback.get(), std::move(result));
     };
     executor(std::move(task), nnDeadline);
 
@@ -238,9 +238,9 @@
     const auto nnToken = nn::CacheToken(token);
 
     Task task = [device, nnModelCache = std::move(nnModelCache),
-                 nnDataCache = std::move(nnDataCache), nnToken, executor, callback] {
+                 nnDataCache = std::move(nnDataCache), nnToken, callback] {
         auto result = device->prepareModelFromCache({}, nnModelCache, nnDataCache, nnToken);
-        notify(callback.get(), std::move(result), executor);
+        notify(callback.get(), std::move(result));
     };
     executor(std::move(task), {});
 
@@ -262,9 +262,9 @@
     const auto nnToken = nn::CacheToken(token);
 
     auto task = [device, nnDeadline, nnModelCache = std::move(nnModelCache),
-                 nnDataCache = std::move(nnDataCache), nnToken, executor, callback] {
+                 nnDataCache = std::move(nnDataCache), nnToken, callback] {
         auto result = device->prepareModelFromCache(nnDeadline, nnModelCache, nnDataCache, nnToken);
-        notify(callback.get(), std::move(result), executor);
+        notify(callback.get(), std::move(result));
     };
     executor(std::move(task), nnDeadline);
 
diff --git a/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp b/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp
index c6055a6..3570a74 100644
--- a/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp
+++ b/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp
@@ -55,15 +55,6 @@
     return result;
 }
 
-nn::GeneralResult<nn::Version> validateRequestForModel(const nn::Request& request,
-                                                       const nn::Model& model) {
-    nn::GeneralResult<nn::Version> version = nn::validateRequestForModel(request, model);
-    if (!version.ok()) {
-        version.error().code = nn::ErrorStatus::INVALID_ARGUMENT;
-    }
-    return version;
-}
-
 class FencedExecutionCallback final : public V1_3::IFencedExecutionCallback {
   public:
     explicit FencedExecutionCallback(const nn::ExecuteFencedInfoCallback& callback)
@@ -144,58 +135,48 @@
 }
 
 nn::GeneralResult<void> execute(const nn::SharedPreparedModel& preparedModel,
-                                const Executor& executor, const V1_0::Request& request,
+                                const V1_0::Request& request,
                                 const sp<V1_0::IExecutionCallback>& callback) {
     if (callback.get() == nullptr) {
         return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
     }
 
-    auto nnRequest = NN_TRY(convertInput(request));
+    const auto nnRequest = NN_TRY(convertInput(request));
 
-    const std::any resource = preparedModel->getUnderlyingResource();
-    if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
-        CHECK(*model != nullptr);
-        NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
+    auto result = preparedModel->execute(nnRequest, nn::MeasureTiming::NO, {}, {}, {}, {});
+
+    if (!result.ok() && result.error().code == nn::ErrorStatus::INVALID_ARGUMENT) {
+        const auto& [message, code, outputShapes] = result.error();
+        return nn::error(code) << message;
     }
 
-    Task task = [preparedModel, nnRequest = std::move(nnRequest), callback] {
-        auto result = preparedModel->execute(nnRequest, nn::MeasureTiming::NO, {}, {}, {}, {});
-        notify(callback.get(), std::move(result));
-    };
-    executor(std::move(task), {});
-
+    notify(callback.get(), std::move(result));
     return {};
 }
 
 nn::GeneralResult<void> execute_1_2(const nn::SharedPreparedModel& preparedModel,
-                                    const Executor& executor, const V1_0::Request& request,
-                                    V1_2::MeasureTiming measure,
+                                    const V1_0::Request& request, V1_2::MeasureTiming measure,
                                     const sp<V1_2::IExecutionCallback>& callback) {
     if (callback.get() == nullptr) {
         return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
     }
 
-    auto nnRequest = NN_TRY(convertInput(request));
+    const auto nnRequest = NN_TRY(convertInput(request));
     const auto nnMeasure = NN_TRY(convertInput(measure));
 
-    const std::any resource = preparedModel->getUnderlyingResource();
-    if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
-        CHECK(*model != nullptr);
-        NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
+    auto result = preparedModel->execute(nnRequest, nnMeasure, {}, {}, {}, {});
+
+    if (!result.ok() && result.error().code == nn::ErrorStatus::INVALID_ARGUMENT) {
+        const auto& [message, code, outputShapes] = result.error();
+        return nn::error(code) << message;
     }
 
-    Task task = [preparedModel, nnRequest = std::move(nnRequest), nnMeasure, callback] {
-        auto result = preparedModel->execute(nnRequest, nnMeasure, {}, {}, {}, {});
-        notify(callback.get(), std::move(result));
-    };
-    executor(std::move(task), {});
-
+    notify(callback.get(), std::move(result));
     return {};
 }
 
 nn::GeneralResult<void> execute_1_3(const nn::SharedPreparedModel& preparedModel,
-                                    const Executor& executor, const V1_3::Request& request,
-                                    V1_2::MeasureTiming measure,
+                                    const V1_3::Request& request, V1_2::MeasureTiming measure,
                                     const V1_3::OptionalTimePoint& deadline,
                                     const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
                                     const sp<V1_3::IExecutionCallback>& callback) {
@@ -203,25 +184,20 @@
         return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
     }
 
-    auto nnRequest = NN_TRY(convertInput(request));
+    const auto nnRequest = NN_TRY(convertInput(request));
     const auto nnMeasure = NN_TRY(convertInput(measure));
     const auto nnDeadline = NN_TRY(convertInput(deadline));
     const auto nnLoopTimeoutDuration = NN_TRY(convertInput(loopTimeoutDuration));
 
-    const std::any resource = preparedModel->getUnderlyingResource();
-    if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
-        CHECK(*model != nullptr);
-        NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
+    auto result =
+            preparedModel->execute(nnRequest, nnMeasure, nnDeadline, nnLoopTimeoutDuration, {}, {});
+
+    if (!result.ok() && result.error().code == nn::ErrorStatus::INVALID_ARGUMENT) {
+        const auto& [message, code, outputShapes] = result.error();
+        return nn::error(code) << message;
     }
 
-    Task task = [preparedModel, nnRequest = std::move(nnRequest), nnMeasure, nnDeadline,
-                 nnLoopTimeoutDuration, callback] {
-        auto result = preparedModel->execute(nnRequest, nnMeasure, nnDeadline,
-                                             nnLoopTimeoutDuration, {}, {});
-        notify(callback.get(), std::move(result));
-    };
-    executor(std::move(task), nnDeadline);
-
+    notify(callback.get(), std::move(result));
     return {};
 }
 
@@ -304,10 +280,9 @@
 
 }  // namespace
 
-PreparedModel::PreparedModel(nn::SharedPreparedModel preparedModel, Executor executor)
-    : kPreparedModel(std::move(preparedModel)), kExecutor(std::move(executor)) {
+PreparedModel::PreparedModel(nn::SharedPreparedModel preparedModel)
+    : kPreparedModel(std::move(preparedModel)) {
     CHECK(kPreparedModel != nullptr);
-    CHECK(kExecutor != nullptr);
 }
 
 nn::SharedPreparedModel PreparedModel::getUnderlyingPreparedModel() const {
@@ -316,7 +291,7 @@
 
 Return<V1_0::ErrorStatus> PreparedModel::execute(const V1_0::Request& request,
                                                  const sp<V1_0::IExecutionCallback>& callback) {
-    auto result = adapter::execute(kPreparedModel, kExecutor, request, callback);
+    auto result = adapter::execute(kPreparedModel, request, callback);
     if (!result.has_value()) {
         auto [message, code] = std::move(result).error();
         LOG(ERROR) << "adapter::PreparedModel::execute failed with " << code << ": " << message;
@@ -329,7 +304,7 @@
 Return<V1_0::ErrorStatus> PreparedModel::execute_1_2(const V1_0::Request& request,
                                                      V1_2::MeasureTiming measure,
                                                      const sp<V1_2::IExecutionCallback>& callback) {
-    auto result = adapter::execute_1_2(kPreparedModel, kExecutor, request, measure, callback);
+    auto result = adapter::execute_1_2(kPreparedModel, request, measure, callback);
     if (!result.has_value()) {
         auto [message, code] = std::move(result).error();
         LOG(ERROR) << "adapter::PreparedModel::execute_1_2 failed with " << code << ": " << message;
@@ -344,7 +319,7 @@
         const V1_3::OptionalTimePoint& deadline,
         const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
         const sp<V1_3::IExecutionCallback>& callback) {
-    auto result = adapter::execute_1_3(kPreparedModel, kExecutor, request, measure, deadline,
+    auto result = adapter::execute_1_3(kPreparedModel, request, measure, deadline,
                                        loopTimeoutDuration, callback);
     if (!result.has_value()) {
         auto [message, code] = std::move(result).error();
@@ -405,8 +380,8 @@
         cb(V1_2::utils::convert(code).value(), nullptr);
         return Void();
     }
-    auto burstContext = std::move(result).value();
-    cb(V1_0::ErrorStatus::NONE, std::move(burstContext));
+    const auto burstContext = std::move(result).value();
+    cb(V1_0::ErrorStatus::NONE, burstContext);
     return Void();
 }
 
diff --git a/neuralnetworks/utils/common/Android.bp b/neuralnetworks/utils/common/Android.bp
index bfba24f..91fca2f 100644
--- a/neuralnetworks/utils/common/Android.bp
+++ b/neuralnetworks/utils/common/Android.bp
@@ -36,6 +36,7 @@
 cc_test {
     name: "neuralnetworks_utils_hal_common_test",
     host_supported: true,
+    tidy_timeout_srcs: ["test/ResilientDeviceTest.cpp"],
     srcs: ["test/*.cpp"],
     static_libs: [
         "libgmock",
diff --git a/neuralnetworks/utils/service/include/nnapi/hal/Service.h b/neuralnetworks/utils/service/include/nnapi/hal/Service.h
index 2fd5237..38d2a54 100644
--- a/neuralnetworks/utils/service/include/nnapi/hal/Service.h
+++ b/neuralnetworks/utils/service/include/nnapi/hal/Service.h
@@ -24,12 +24,16 @@
 
 namespace android::hardware::neuralnetworks::service {
 
-struct SharedDeviceAndUpdatability {
-    nn::SharedDevice device;
-    bool isDeviceUpdatable = false;
-};
-
-std::vector<SharedDeviceAndUpdatability> getDevices(bool includeUpdatableDrivers);
+/**
+ * @brief Get the NNAPI sAIDL and HIDL services declared in the VINTF.
+ *
+ * @pre maxFeatureLevelAllowed >= Version::Level::FEATURE_LEVEL_5
+ *
+ * @param maxFeatureLevelAllowed Maximum version of driver allowed to be used. Any driver version
+ *     exceeding this must be clamped to `maxFeatureLevelAllowed`.
+ * @return A list of devices and whether each device is updatable or not.
+ */
+std::vector<nn::SharedDevice> getDevices(nn::Version::Level maxFeatureLevelAllowed);
 
 }  // namespace android::hardware::neuralnetworks::service
 
diff --git a/neuralnetworks/utils/service/src/Service.cpp b/neuralnetworks/utils/service/src/Service.cpp
index 2286288..dd37dae 100644
--- a/neuralnetworks/utils/service/src/Service.cpp
+++ b/neuralnetworks/utils/service/src/Service.cpp
@@ -51,7 +51,7 @@
 using getDeviceFn = std::add_pointer_t<nn::GeneralResult<nn::SharedDevice>(const std::string&)>;
 
 void getHidlDevicesForVersion(const std::string& descriptor, getDeviceFn getDevice,
-                              std::vector<SharedDeviceAndUpdatability>* devices,
+                              std::vector<nn::SharedDevice>* devices,
                               std::unordered_set<std::string>* registeredDevices) {
     CHECK(devices != nullptr);
     CHECK(registeredDevices != nullptr);
@@ -63,7 +63,7 @@
             if (maybeDevice.has_value()) {
                 auto device = std::move(maybeDevice).value();
                 CHECK(device != nullptr);
-                devices->push_back({.device = std::move(device)});
+                devices->push_back(std::move(device));
             } else {
                 LOG(ERROR) << "getDevice(" << name << ") failed with " << maybeDevice.error().code
                            << ": " << maybeDevice.error().message;
@@ -72,9 +72,9 @@
     }
 }
 
-void getAidlDevices(std::vector<SharedDeviceAndUpdatability>* devices,
+void getAidlDevices(std::vector<nn::SharedDevice>* devices,
                     std::unordered_set<std::string>* registeredDevices,
-                    bool includeUpdatableDrivers) {
+                    nn::Version::Level maxFeatureLevelAllowed) {
     CHECK(devices != nullptr);
     CHECK(registeredDevices != nullptr);
 
@@ -91,21 +91,12 @@
     }
 
     for (const auto& name : names) {
-        bool isDeviceUpdatable = false;
-        if (__builtin_available(android __NNAPI_AIDL_MIN_ANDROID_API__, *)) {
-            const auto instance = std::string(aidl_hal::IDevice::descriptor) + '/' + name;
-            isDeviceUpdatable = AServiceManager_isUpdatableViaApex(instance.c_str());
-        }
-        if (isDeviceUpdatable && !includeUpdatableDrivers) {
-            continue;
-        }
         if (const auto [it, unregistered] = registeredDevices->insert(name); unregistered) {
-            auto maybeDevice = aidl_hal::utils::getDevice(name);
+            auto maybeDevice = aidl_hal::utils::getDevice(name, maxFeatureLevelAllowed);
             if (maybeDevice.has_value()) {
                 auto device = std::move(maybeDevice).value();
                 CHECK(device != nullptr);
-                devices->push_back(
-                        {.device = std::move(device), .isDeviceUpdatable = isDeviceUpdatable});
+                devices->push_back(std::move(device));
             } else {
                 LOG(ERROR) << "getDevice(" << name << ") failed with " << maybeDevice.error().code
                            << ": " << maybeDevice.error().message;
@@ -116,11 +107,13 @@
 
 }  // namespace
 
-std::vector<SharedDeviceAndUpdatability> getDevices(bool includeUpdatableDrivers) {
-    std::vector<SharedDeviceAndUpdatability> devices;
+std::vector<nn::SharedDevice> getDevices(nn::Version::Level maxFeatureLevelAllowed) {
+    std::vector<nn::SharedDevice> devices;
     std::unordered_set<std::string> registeredDevices;
 
-    getAidlDevices(&devices, &registeredDevices, includeUpdatableDrivers);
+    CHECK_GE(maxFeatureLevelAllowed, nn::Version::Level::FEATURE_LEVEL_5);
+
+    getAidlDevices(&devices, &registeredDevices, maxFeatureLevelAllowed);
 
     getHidlDevicesForVersion(V1_3::IDevice::descriptor, &V1_3::utils::getDevice, &devices,
                              &registeredDevices);
diff --git a/radio/1.0/vts/functional/sap_hidl_hal_test.cpp b/radio/1.0/vts/functional/sap_hidl_hal_test.cpp
index fe10587..5224624 100644
--- a/radio/1.0/vts/functional/sap_hidl_hal_test.cpp
+++ b/radio/1.0/vts/functional/sap_hidl_hal_test.cpp
@@ -16,8 +16,37 @@
 
 #include <sap_hidl_hal_utils.h>
 
+bool isServiceValidForDeviceConfiguration(hidl_string& serviceName) {
+    if (isSsSsEnabled()) {
+        // Device is configured as SSSS.
+        if (serviceName != SAP_SERVICE_SLOT1_NAME) {
+            LOG(DEBUG) << "Not valid for SSSS device.";
+            return false;
+        }
+    } else if (isDsDsEnabled()) {
+        // Device is configured as DSDS.
+        if (serviceName != SAP_SERVICE_SLOT1_NAME && serviceName != SAP_SERVICE_SLOT2_NAME) {
+            LOG(DEBUG) << "Not valid for DSDS device.";
+            return false;
+        }
+    } else if (isTsTsEnabled()) {
+        // Device is configured as TSTS.
+        if (serviceName != SAP_SERVICE_SLOT1_NAME && serviceName != SAP_SERVICE_SLOT2_NAME &&
+            serviceName != SAP_SERVICE_SLOT3_NAME) {
+            LOG(DEBUG) << "Not valid for TSTS device.";
+            return false;
+        }
+    }
+    return true;
+}
+
 void SapHidlTest::SetUp() {
-    sap = ISap::getService(GetParam());
+    hidl_string serviceName = GetParam();
+    if (!isServiceValidForDeviceConfiguration(serviceName)) {
+        LOG(DEBUG) << "Skipped the test due to device configuration.";
+        GTEST_SKIP();
+    }
+    sap = ISap::getService(serviceName);
     ASSERT_NE(sap, nullptr);
 
     sapCb = new SapCallback(*this);
diff --git a/radio/1.0/vts/functional/sap_hidl_hal_utils.h b/radio/1.0/vts/functional/sap_hidl_hal_utils.h
index 2fc9ae3..8e86591 100644
--- a/radio/1.0/vts/functional/sap_hidl_hal_utils.h
+++ b/radio/1.0/vts/functional/sap_hidl_hal_utils.h
@@ -36,7 +36,15 @@
 using ::android::sp;
 
 #define TIMEOUT_PERIOD 40
-#define SAP_SERVICE_NAME "slot1"
+
+// HAL instance name for SIM slot 1 or single SIM device
+#define SAP_SERVICE_SLOT1_NAME "slot1"
+
+// HAL instance name for SIM slot 2 on dual SIM device
+#define SAP_SERVICE_SLOT2_NAME "slot2"
+
+// HAL instance name for SIM slot 3 on triple SIM device
+#define SAP_SERVICE_SLOT3_NAME "slot3"
 
 class SapHidlTest;
 
diff --git a/radio/1.6/Android.bp b/radio/1.6/Android.bp
index 4b79c0a..2137e8d 100644
--- a/radio/1.6/Android.bp
+++ b/radio/1.6/Android.bp
@@ -29,4 +29,5 @@
         "android.hidl.safe_union@1.0",
     ],
     gen_java: true,
+    system_ext_specific: true,
 }
diff --git a/radio/aidl/android/hardware/radio/data/IRadioData.aidl b/radio/aidl/android/hardware/radio/data/IRadioData.aidl
index e1ba568..0171d39 100644
--- a/radio/aidl/android/hardware/radio/data/IRadioData.aidl
+++ b/radio/aidl/android/hardware/radio/data/IRadioData.aidl
@@ -65,6 +65,7 @@
     /**
      * Deactivate packet data connection and remove from the data call list. An
      * unsolDataCallListChanged() must be sent when data connection is deactivated.
+     * Any return value other than RadioError::NONE will remove the network from the list.
      *
      * @param serial Serial number of request.
      * @param cid Data call id.
@@ -76,8 +77,7 @@
 
     /**
      * Returns the data call list. An entry is added when a setupDataCall() is issued and removed
-     * on a deactivateDataCall(). The list is emptied when setRadioPower()  off/on issued or when
-     * the vendor HAL or modem crashes.
+     * on a deactivateDataCall(). The list is emptied when the vendor HAL crashes.
      *
      * @param serial Serial number of request.
      *
diff --git a/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl b/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl
index bbc8d07..88b6c1b 100644
--- a/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl
+++ b/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl
@@ -67,7 +67,7 @@
      *
      * Valid errors returned:
      *   RadioError:REQUEST_NOT_SUPPORTED may be returned when HAL 1.2 or higher is supported.
-     *   RadioError:NONE
+     *   RadioError:NONE indicates success. Any other error will remove the network from the list.
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_CALL_ID
      *   RadioError:INVALID_STATE
diff --git a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
index 22b9ede..d5e2a8d 100644
--- a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
+++ b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
@@ -228,7 +228,7 @@
 ScopedAStatus RadioNetwork::setNetworkSelectionModeManual(  //
         int32_t serial, const std::string& opNumeric, AccessNetwork ran) {
     LOG_CALL << serial;
-    mHal1_5->setNetworkSelectionModeManual_1_5(serial, opNumeric, V1_5::RadioAccessNetworks(ran));
+    mHal1_5->setNetworkSelectionModeManual_1_5(serial, opNumeric, toRadioAccessNetworks(ran));
     return ok();
 }
 
diff --git a/radio/aidl/compat/libradiocompat/network/structs.cpp b/radio/aidl/compat/libradiocompat/network/structs.cpp
index c1d9b35..d0b3b90 100644
--- a/radio/aidl/compat/libradiocompat/network/structs.cpp
+++ b/radio/aidl/compat/libradiocompat/network/structs.cpp
@@ -98,17 +98,56 @@
     return hidl;
 }
 
+AccessNetwork fromRadioAccessNetwork(V1_5::RadioAccessNetworks ran) {
+    switch (ran) {
+        case V1_5::RadioAccessNetworks::UNKNOWN:
+            return AccessNetwork::UNKNOWN;
+        case V1_5::RadioAccessNetworks::GERAN:
+            return AccessNetwork::GERAN;
+        case V1_5::RadioAccessNetworks::UTRAN:
+            return AccessNetwork::UTRAN;
+        case V1_5::RadioAccessNetworks::EUTRAN:
+            return AccessNetwork::EUTRAN;
+        case V1_5::RadioAccessNetworks::CDMA2000:
+            return AccessNetwork::CDMA2000;
+        case V1_5::RadioAccessNetworks::NGRAN:
+            return AccessNetwork::NGRAN;
+        default:
+            return AccessNetwork::UNKNOWN;
+    }
+}
+
 aidl::RadioAccessSpecifier toAidl(const V1_5::RadioAccessSpecifier& spec) {
     return {
-            .accessNetwork = AccessNetwork(spec.radioAccessNetwork),
+            .accessNetwork = fromRadioAccessNetwork(spec.radioAccessNetwork),
             .bands = toAidl(spec.bands),
             .channels = spec.channels,
     };
 }
 
+V1_5::RadioAccessNetworks toRadioAccessNetworks(AccessNetwork val) {
+    switch (val) {
+        case AccessNetwork::UNKNOWN:
+            return V1_5::RadioAccessNetworks::UNKNOWN;
+        case AccessNetwork::GERAN:
+            return V1_5::RadioAccessNetworks::GERAN;
+        case AccessNetwork::UTRAN:
+            return V1_5::RadioAccessNetworks::UTRAN;
+        case AccessNetwork::EUTRAN:
+            return V1_5::RadioAccessNetworks::EUTRAN;
+        case AccessNetwork::CDMA2000:
+            return V1_5::RadioAccessNetworks::CDMA2000;
+        case AccessNetwork::NGRAN:
+            return V1_5::RadioAccessNetworks::NGRAN;
+        case AccessNetwork::IWLAN:
+        default:
+            return V1_5::RadioAccessNetworks::UNKNOWN;
+    }
+}
+
 V1_5::RadioAccessSpecifier toHidl(const aidl::RadioAccessSpecifier& spec) {
     return {
-            .radioAccessNetwork = V1_5::RadioAccessNetworks{spec.accessNetwork},
+            .radioAccessNetwork = toRadioAccessNetworks(spec.accessNetwork),
             .bands = toHidl(spec.bands),
             .channels = spec.channels,
     };
diff --git a/radio/aidl/compat/libradiocompat/network/structs.h b/radio/aidl/compat/libradiocompat/network/structs.h
index aaa49a0..6a9a219 100644
--- a/radio/aidl/compat/libradiocompat/network/structs.h
+++ b/radio/aidl/compat/libradiocompat/network/structs.h
@@ -49,6 +49,8 @@
 
 ::aidl::android::hardware::radio::network::RadioAccessSpecifier  //
 toAidl(const V1_5::RadioAccessSpecifier& spec);
+V1_5::RadioAccessNetworks  //
+toRadioAccessNetworks(::aidl::android::hardware::radio::AccessNetwork val);
 V1_5::RadioAccessSpecifier  //
 toHidl(const ::aidl::android::hardware::radio::network::RadioAccessSpecifier& spec);
 
diff --git a/radio/aidl/vts/Android.bp b/radio/aidl/vts/Android.bp
index 8060e4b..021ee89 100644
--- a/radio/aidl/vts/Android.bp
+++ b/radio/aidl/vts/Android.bp
@@ -27,6 +27,12 @@
         "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
     ],
+    tidy_timeout_srcs: [
+        "radio_messaging_test.cpp",
+        "radio_network_test.cpp",
+        "radio_sim_test.cpp",
+        "radio_voice_test.cpp",
+    ],
     srcs: [
         "radio_aidl_hal_utils.cpp",
         "radio_config_indication.cpp",
@@ -66,9 +72,8 @@
         "android.hardware.radio.sim-V1-ndk",
         "android.hardware.radio.voice-V1-ndk",
     ],
-    // TODO(b/210712359): enable after b/207695009 is resolved.
-    //test_suites: [
-    //    "general-tests",
-    //    "vts",
-    //],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/radio/aidl/vts/AndroidTest.xml b/radio/aidl/vts/AndroidTest.xml
new file mode 100644
index 0000000..36381d1
--- /dev/null
+++ b/radio/aidl/vts/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VtsHalRadioTargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.MultiSimPreparer" />
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalRadioTargetTest->/data/local/tmp/VtsHalRadioTargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="native-test-timeout" value="300000" /> <!-- 5 min -->
+        <option name="module-name" value="VtsHalRadioTargetTest" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.cpp b/radio/aidl/vts/radio_aidl_hal_utils.cpp
index dc61a3c..8618851 100644
--- a/radio/aidl/vts/radio_aidl_hal_utils.cpp
+++ b/radio/aidl/vts/radio_aidl_hal_utils.cpp
@@ -24,6 +24,7 @@
 #define WAIT_TIMEOUT_PERIOD 75
 
 sim::CardStatus cardStatus = {};
+config::SimSlotStatus slotStatus = {};
 int serial = 0;
 int count_ = 0;
 
@@ -107,7 +108,7 @@
 
 bool stringEndsWith(std::string const& string, std::string const& end) {
     if (string.size() >= end.size()) {
-        return (0 == string.compare(string.size() - end.size() - 1, end.size(), end));
+        return std::equal(end.rbegin(), end.rend(), string.rbegin());
     } else {
         return false;
     }
@@ -116,7 +117,7 @@
 bool isServiceValidForDeviceConfiguration(std::string& serviceName) {
     if (isSsSsEnabled()) {
         // Device is configured as SSSS.
-        if (stringEndsWith(serviceName, RADIO_SERVICE_SLOT1_NAME)) {
+        if (!stringEndsWith(serviceName, RADIO_SERVICE_SLOT1_NAME)) {
             ALOGI("%s instance is not valid for SSSS device.", serviceName.c_str());
             return false;
         }
@@ -204,3 +205,22 @@
     EXPECT_EQ(serial, radioSimRsp->rspInfo.serial);
     EXPECT_EQ(RadioError::NONE, radioSimRsp->rspInfo.error);
 }
+
+void RadioServiceTest::updateSimSlotStatus() {
+    // Update SimSlotStatus from RadioConfig
+    std::shared_ptr<RadioConfigResponse> radioConfigRsp =
+            ndk::SharedRefBase::make<RadioConfigResponse>(*this);
+    std::shared_ptr<RadioConfigIndication> radioConfigInd =
+            ndk::SharedRefBase::make<RadioConfigIndication>(*this);
+    radio_config->setResponseFunctions(radioConfigRsp, radioConfigInd);
+    serial = GetRandomSerialNumber();
+    radio_config->getSimSlotsStatus(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioConfigRsp->rspInfo.type);
+    EXPECT_EQ(serial, radioConfigRsp->rspInfo.serial);
+    EXPECT_EQ(RadioError::NONE, radioConfigRsp->rspInfo.error);
+    // assuming only 1 slot
+    for (const SimSlotStatus& slotStatusResponse : radioConfigRsp->simSlotStatus) {
+        slotStatus = slotStatusResponse;
+    }
+}
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.h b/radio/aidl/vts/radio_aidl_hal_utils.h
index 414ffbc..d6f7bf7 100644
--- a/radio/aidl/vts/radio_aidl_hal_utils.h
+++ b/radio/aidl/vts/radio_aidl_hal_utils.h
@@ -20,6 +20,7 @@
 #include <aidl/Vintf.h>
 #include <aidl/android/hardware/radio/RadioError.h>
 #include <aidl/android/hardware/radio/config/IRadioConfig.h>
+#include <aidl/android/hardware/radio/config/SimSlotStatus.h>
 #include <aidl/android/hardware/radio/network/RegState.h>
 #include <aidl/android/hardware/radio/sim/CardStatus.h>
 #include <aidl/android/hardware/radio/sim/IRadioSim.h>
@@ -27,10 +28,12 @@
 #include <vector>
 
 using namespace aidl::android::hardware::radio;
+using aidl::android::hardware::radio::config::SimSlotStatus;
 using aidl::android::hardware::radio::network::RegState;
 using aidl::android::hardware::radio::sim::CardStatus;
 
 extern CardStatus cardStatus;
+extern SimSlotStatus slotStatus;
 extern int serial;
 extern int count_;
 
@@ -141,4 +144,7 @@
 
     /* Update SIM card status */
     void updateSimCardStatus();
+
+    /* Update SIM slot status */
+    void updateSimSlotStatus();
 };
diff --git a/radio/aidl/vts/radio_config_response.cpp b/radio/aidl/vts/radio_config_response.cpp
index 8d81605..7384f87 100644
--- a/radio/aidl/vts/radio_config_response.cpp
+++ b/radio/aidl/vts/radio_config_response.cpp
@@ -19,8 +19,9 @@
 RadioConfigResponse::RadioConfigResponse(RadioServiceTest& parent) : parent_config(parent) {}
 
 ndk::ScopedAStatus RadioConfigResponse::getSimSlotsStatusResponse(
-        const RadioResponseInfo& info, const std::vector<SimSlotStatus>& /* slotStatus */) {
+        const RadioResponseInfo& info, const std::vector<SimSlotStatus>& slotStatus) {
     rspInfo = info;
+    simSlotStatus = slotStatus;
     parent_config.notify(info.serial);
     return ndk::ScopedAStatus::ok();
 }
diff --git a/radio/aidl/vts/radio_config_test.cpp b/radio/aidl/vts/radio_config_test.cpp
index a271b8a..83c4de0 100644
--- a/radio/aidl/vts/radio_config_test.cpp
+++ b/radio/aidl/vts/radio_config_test.cpp
@@ -24,11 +24,6 @@
 void RadioConfigTest::SetUp() {
     std::string serviceName = GetParam();
 
-    if (!isServiceValidForDeviceConfiguration(serviceName)) {
-        ALOGI("Skipped the test due to device configuration.");
-        GTEST_SKIP();
-    }
-
     radio_config = IRadioConfig::fromBinder(
             ndk::SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
     ASSERT_NE(nullptr, radio_config.get());
@@ -44,6 +39,19 @@
     radio_config->setResponseFunctions(radioRsp_config, radioInd_config);
 }
 
+void RadioConfigTest::updateSimSlotStatus() {
+    serial = GetRandomSerialNumber();
+    radio_config->getSimSlotsStatus(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_config->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_config->rspInfo.serial);
+    EXPECT_EQ(RadioError::NONE, radioRsp_config->rspInfo.error);
+    // assuming only 1 slot
+    for (const SimSlotStatus& slotStatusResponse : radioRsp_config->simSlotStatus) {
+        slotStatus = slotStatusResponse;
+    }
+}
+
 /*
  * Test IRadioConfig.getHalDeviceCapabilities() for the response returned.
  */
@@ -153,3 +161,46 @@
                                  {RadioError::INVALID_ARGUMENTS, RadioError::RADIO_NOT_AVAILABLE,
                                   RadioError::INTERNAL_ERR}));
 }
+
+/*
+ * Test IRadioConfig.setSimSlotsMapping() for the response returned.
+ */
+TEST_P(RadioConfigTest, setSimSlotsMapping) {
+    serial = GetRandomSerialNumber();
+    SlotPortMapping slotPortMapping;
+    slotPortMapping.physicalSlotId = 0;
+    slotPortMapping.portId = 0;
+    std::vector<SlotPortMapping> slotPortMappingList = {slotPortMapping};
+    ndk::ScopedAStatus res = radio_config->setSimSlotsMapping(serial, slotPortMappingList);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_config->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_config->rspInfo.serial);
+    ALOGI("setSimSlotsMapping, rspInfo.error = %s\n",
+          toString(radioRsp_config->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_config->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
+ * Test IRadioConfig.getSimSlotStatus() for the response returned.
+ */
+
+TEST_P(RadioConfigTest, checkPortInfoExistsAndPortActive) {
+    serial = GetRandomSerialNumber();
+    ndk::ScopedAStatus res = radio_config->getSimSlotsStatus(serial);
+    ASSERT_OK(res);
+    ALOGI("getSimSlotsStatus, rspInfo.error = %s\n",
+          toString(radioRsp_config->rspInfo.error).c_str());
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_config->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_config->rspInfo.serial);
+    if (radioRsp_config->rspInfo.error == RadioError::NONE) {
+        // check if cardState is present, portInfo size should be more than 0
+        for (const SimSlotStatus& slotStatusResponse : radioRsp_config->simSlotStatus) {
+            if (slotStatusResponse.cardState == CardStatus::STATE_PRESENT) {
+                ASSERT_TRUE(slotStatusResponse.portInfo.size() > 0);
+                ASSERT_TRUE(slotStatusResponse.portInfo[0].portActive);
+            }
+        }
+    }
+}
diff --git a/radio/aidl/vts/radio_config_utils.h b/radio/aidl/vts/radio_config_utils.h
index 465c106..3db430d 100644
--- a/radio/aidl/vts/radio_config_utils.h
+++ b/radio/aidl/vts/radio_config_utils.h
@@ -38,6 +38,7 @@
     RadioResponseInfo rspInfo;
     PhoneCapability phoneCap;
     bool modemReducedFeatureSet1;
+    std::vector<SimSlotStatus> simSlotStatus;
 
     virtual ndk::ScopedAStatus getSimSlotsStatusResponse(
             const RadioResponseInfo& info, const std::vector<SimSlotStatus>& slotStatus) override;
@@ -77,6 +78,8 @@
   public:
     virtual void SetUp() override;
     ndk::ScopedAStatus updateSimCardStatus();
+    /* Override updateSimSlotStatus in RadioServiceTest to not call setResponseFunctions */
+    void updateSimSlotStatus();
 
     /* radio config service handle in RadioServiceTest */
     /* radio config response handle */
diff --git a/radio/aidl/vts/radio_sim_test.cpp b/radio/aidl/vts/radio_sim_test.cpp
index 64474c9..f94a2a0 100644
--- a/radio/aidl/vts/radio_sim_test.cpp
+++ b/radio/aidl/vts/radio_sim_test.cpp
@@ -108,7 +108,13 @@
     // have CardStatus::STATE_PRESENT after turning the power back on
     if (radioRsp_sim->rspInfo.error == RadioError::NONE) {
         updateSimCardStatus();
+        updateSimSlotStatus();
         EXPECT_EQ(CardStatus::STATE_PRESENT, cardStatus.cardState);
+        EXPECT_EQ(CardStatus::STATE_PRESENT, slotStatus.cardState);
+        if (CardStatus::STATE_PRESENT == slotStatus.cardState) {
+            ASSERT_TRUE(slotStatus.portInfo[0].portActive);
+            EXPECT_EQ(0, cardStatus.slotMap.portId);
+        }
     }
 }
 
@@ -376,8 +382,6 @@
  * Test IRadioSim.setAllowedCarriers() for the response returned.
  */
 TEST_P(RadioSimTest, setAllowedCarriers) {
-    // TODO (b/210712359): remove once shim supports 1.4 or alternative is found
-    GTEST_SKIP();
     serial = GetRandomSerialNumber();
     CarrierRestrictions carrierRestrictions;
     memset(&carrierRestrictions, 0, sizeof(carrierRestrictions));
@@ -411,7 +415,8 @@
                 sleep(2);
                 updateSimCardStatus();
             }
-            EXPECT_EQ(CardStatus::STATE_RESTRICTED, cardStatus.cardState);
+            // TODO: uncomment once CF fully supports setAllowedCarriers
+            // EXPECT_EQ(CardStatus::STATE_RESTRICTED, cardStatus.cardState);
         }
 
         /* Verify that configuration was set correctly, retrieving it from the modem */
diff --git a/radio/aidl/vts/radio_voice_test.cpp b/radio/aidl/vts/radio_voice_test.cpp
index eec28b1..249ee63 100644
--- a/radio/aidl/vts/radio_voice_test.cpp
+++ b/radio/aidl/vts/radio_voice_test.cpp
@@ -943,3 +943,37 @@
     }
     LOG(DEBUG) << "cancelPendingUssd finished";
 }
+
+/*
+ * Test IRadioVoice.isVoNrEnabled() for the response returned.
+ */
+TEST_P(RadioVoiceTest, isVoNrEnabled) {
+    LOG(DEBUG) << "isVoNrEnabled";
+    serial = GetRandomSerialNumber();
+
+    radio_voice->isVoNrEnabled(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_voice->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_voice->rspInfo.serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_voice->rspInfo.error,
+                                 {RadioError::REQUEST_NOT_SUPPORTED, RadioError::NONE}));
+    LOG(DEBUG) << "isVoNrEnabled finished";
+}
+
+/*
+ * Test IRadioVoice.setVoNrEnabled() for the response returned.
+ */
+TEST_P(RadioVoiceTest, setVoNrEnabled) {
+    LOG(DEBUG) << "setVoNrEnabled";
+    serial = GetRandomSerialNumber();
+
+    radio_voice->setVoNrEnabled(serial, true);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_voice->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_voice->rspInfo.serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_voice->rspInfo.error,
+                                 {RadioError::REQUEST_NOT_SUPPORTED, RadioError::NONE}));
+    LOG(DEBUG) << "setVoNrEnabled finished";
+}
diff --git a/security/dice/aidl/Android.bp b/security/dice/aidl/Android.bp
index 01bc91e..8c31e26 100644
--- a/security/dice/aidl/Android.bp
+++ b/security/dice/aidl/Android.bp
@@ -38,6 +38,10 @@
                 enabled: true,
             },
             apps_enabled: false,
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.compos",
+            ],
         },
         rust: {
             enabled: true,
diff --git a/security/dice/aidl/default/Android.bp b/security/dice/aidl/default/Android.bp
new file mode 100644
index 0000000..b67a44a
--- /dev/null
+++ b/security/dice/aidl/default/Android.bp
@@ -0,0 +1,30 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+rust_binary {
+    name: "android.hardware.security.dice-service.non-secure-software",
+    srcs: ["service.rs"],
+    relative_install_path: "hw",
+    vendor: true,
+    rustlibs: [
+        "android.hardware.security.dice-V1-rust",
+        "libdiced_open_dice_cbor",
+        "libdiced_sample_inputs",
+        "libdiced_vendor",
+        "libandroid_logger",
+        "libanyhow",
+        "libbinder_rs",
+        "liblog_rust",
+        "libserde",
+    ],
+    init_rc: ["android.hardware.security.dice-service.non-secure-software.rc"],
+    vintf_fragments: [
+        "android.hardware.security.dice-service.non-secure-software.xml",
+    ],
+}
diff --git a/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.rc b/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.rc
new file mode 100644
index 0000000..28e43c3
--- /dev/null
+++ b/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.rc
@@ -0,0 +1,9 @@
+service vendor.dice /vendor/bin/hw/android.hardware.security.dice-service.non-secure-software
+    class early_hal
+    user nobody
+    # The diced HAL cannot be allowed to restart. When it crashes for any reason.
+    # it loses security critical state. The only remedy is to restart the device.
+    # This may be implementation depended. It is safe to restart the HAL if the
+    # state change during a call to "demote" is is preserved.
+    # see android/hardware/security/dice/IDiceDevice.aidl for details on "demote".
+    oneshot
diff --git a/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.xml b/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.xml
new file mode 100644
index 0000000..94ef243
--- /dev/null
+++ b/security/dice/aidl/default/android.hardware.security.dice-service.non-secure-software.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.security.dice</name>
+        <fqname>IDiceDevice/default</fqname>
+    </hal>
+</manifest>
\ No newline at end of file
diff --git a/security/dice/aidl/default/service.rs b/security/dice/aidl/default/service.rs
new file mode 100644
index 0000000..eebf333
--- /dev/null
+++ b/security/dice/aidl/default/service.rs
@@ -0,0 +1,107 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Main entry point for the android.hardware.security.dice service.
+
+use anyhow::Result;
+use diced::{
+    dice,
+    hal_node::{DiceArtifacts, DiceDevice, ResidentHal, UpdatableDiceArtifacts},
+};
+use diced_sample_inputs::make_sample_bcc_and_cdis;
+use serde::{Deserialize, Serialize};
+use std::convert::TryInto;
+use std::panic;
+use std::sync::Arc;
+
+static DICE_HAL_SERVICE_NAME: &str = "android.hardware.security.dice.IDiceDevice/default";
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+struct InsecureSerializableArtifacts {
+    cdi_attest: [u8; dice::CDI_SIZE],
+    cdi_seal: [u8; dice::CDI_SIZE],
+    bcc: Vec<u8>,
+}
+
+impl DiceArtifacts for InsecureSerializableArtifacts {
+    fn cdi_attest(&self) -> &[u8; dice::CDI_SIZE] {
+        &self.cdi_attest
+    }
+    fn cdi_seal(&self) -> &[u8; dice::CDI_SIZE] {
+        &self.cdi_seal
+    }
+    fn bcc(&self) -> Vec<u8> {
+        self.bcc.clone()
+    }
+}
+
+impl UpdatableDiceArtifacts for InsecureSerializableArtifacts {
+    fn with_artifacts<F, T>(&self, f: F) -> Result<T>
+    where
+        F: FnOnce(&dyn DiceArtifacts) -> Result<T>,
+    {
+        f(self)
+    }
+    fn update(self, new_artifacts: &impl DiceArtifacts) -> Result<Self> {
+        Ok(Self {
+            cdi_attest: *new_artifacts.cdi_attest(),
+            cdi_seal: *new_artifacts.cdi_seal(),
+            bcc: new_artifacts.bcc(),
+        })
+    }
+}
+
+fn main() {
+    android_logger::init_once(
+        android_logger::Config::default()
+            .with_tag("android.hardware.security.dice")
+            .with_min_level(log::Level::Debug),
+    );
+    // Redirect panic messages to logcat.
+    panic::set_hook(Box::new(|panic_info| {
+        log::error!("{}", panic_info);
+    }));
+
+    // Saying hi.
+    log::info!("android.hardware.security.dice is starting.");
+
+    let (cdi_attest, cdi_seal, bcc) =
+        make_sample_bcc_and_cdis().expect("Failed to construct sample dice chain.");
+
+    let hal_impl = Arc::new(
+        unsafe {
+            // Safety: ResidentHal cannot be used in multi threaded processes.
+            // This service does not start a thread pool. The main thread is the only thread
+            // joining the thread pool, thereby keeping the process single threaded.
+            ResidentHal::new(InsecureSerializableArtifacts {
+                cdi_attest: cdi_attest[..]
+                    .try_into()
+                    .expect("Failed to convert cdi_attest to array reference."),
+                cdi_seal: cdi_seal[..]
+                    .try_into()
+                    .expect("Failed to convert cdi_seal to array reference."),
+                bcc,
+            })
+        }
+        .expect("Failed to create ResidentHal implementation."),
+    );
+
+    let hal = DiceDevice::new_as_binder(hal_impl).expect("Failed to construct hal service.");
+
+    binder::add_service(DICE_HAL_SERVICE_NAME, hal.as_binder())
+        .expect("Failed to register IDiceDevice Service");
+
+    log::info!("Joining thread pool now.");
+    binder::ProcessState::join_thread_pool();
+}
diff --git a/security/dice/aidl/vts/functional/Android.bp b/security/dice/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..f5bc949
--- /dev/null
+++ b/security/dice/aidl/vts/functional/Android.bp
@@ -0,0 +1,54 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+rust_test {
+    name: "VtsAidlDiceTargetTest",
+    srcs: [
+        "dice_test.rs",
+    ],
+    require_root: true,
+    auto_gen_config: true,
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+
+    rustlibs: [
+        "android.hardware.security.dice-V1-rust",
+        "libanyhow",
+        "libbinder_rs",
+        "libdiced_open_dice_cbor",
+        "libdiced_sample_inputs",
+        "libdiced_utils",
+        "libkeystore2_vintf_rust",
+    ],
+}
+
+rust_test {
+    name: "VtsAidlDiceDemoteTargetTest",
+    srcs: [
+        "dice_demote_test.rs",
+    ],
+
+    test_config: "VtsAidlDiceDemoteTargetTest.xml",
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+
+    rustlibs: [
+        "android.hardware.security.dice-V1-rust",
+        "libanyhow",
+        "libbinder_rs",
+        "libdiced_open_dice_cbor",
+        "libdiced_sample_inputs",
+        "libdiced_utils",
+        "libkeystore2_vintf_rust",
+    ],
+}
diff --git a/security/dice/aidl/vts/functional/VtsAidlDiceDemoteTargetTest.xml b/security/dice/aidl/vts/functional/VtsAidlDiceDemoteTargetTest.xml
new file mode 100644
index 0000000..2991580
--- /dev/null
+++ b/security/dice/aidl/vts/functional/VtsAidlDiceDemoteTargetTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<configuration description="Config to run VtsAidlDiceDemoteTargetTest device tests.">
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsAidlDiceDemoteTargetTest->/data/local/tmp/VtsAidlDiceDemoteTargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.rust.RustBinaryTest" >
+        <option name="test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsAidlDiceDemoteTargetTest" />
+    </test>
+    <target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer" />
+
+</configuration>
\ No newline at end of file
diff --git a/security/dice/aidl/vts/functional/dice_demote_test.rs b/security/dice/aidl/vts/functional/dice_demote_test.rs
new file mode 100644
index 0000000..02ff2a4
--- /dev/null
+++ b/security/dice/aidl/vts/functional/dice_demote_test.rs
@@ -0,0 +1,67 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use diced_open_dice_cbor as dice;
+use diced_sample_inputs;
+use diced_utils;
+use std::convert::TryInto;
+
+mod utils;
+use utils::with_connection;
+
+// This test calls derive with an empty argument vector, then demotes the HAL using
+// a set of three input values, and then calls derive with empty argument vector again.
+// It then performs the same three derivation steps on the result of the former and compares
+// the result to the result of the latter.
+#[test]
+fn demote_test() {
+    with_connection(|device| {
+        let input_values = diced_sample_inputs::get_input_values_vector();
+        let former = device.derive(&[]).expect("Trying to call derive.");
+        device
+            .demote(&input_values)
+            .expect("Trying to call demote with input values.");
+
+        let latter = device
+            .derive(&[])
+            .expect("Trying to call derive after demote.");
+
+        let artifacts = diced_utils::ResidentArtifacts::new(
+            former.cdiAttest[..].try_into().unwrap(),
+            former.cdiSeal[..].try_into().unwrap(),
+            &former.bcc.data,
+        )
+        .unwrap();
+
+        let input_values: Vec<diced_utils::InputValues> = input_values
+            .iter()
+            .map(|v| v.into())
+            .collect();
+
+        let artifacts = artifacts
+            .execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues))
+            .unwrap();
+        let (cdi_attest, cdi_seal, bcc) = artifacts.into_tuple();
+        let from_former = diced_utils::make_bcc_handover(
+            cdi_attest[..].try_into().unwrap(),
+            cdi_seal[..].try_into().unwrap(),
+            &bcc,
+        )
+        .unwrap();
+        // TODO b/204938506 when we have a parser/verifier, check equivalence rather
+        // than bit by bit equality.
+        assert_eq!(latter, from_former);
+        Ok(())
+    })
+}
diff --git a/security/dice/aidl/vts/functional/dice_test.rs b/security/dice/aidl/vts/functional/dice_test.rs
new file mode 100644
index 0000000..574b634
--- /dev/null
+++ b/security/dice/aidl/vts/functional/dice_test.rs
@@ -0,0 +1,82 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use diced_open_dice_cbor as dice;
+use diced_sample_inputs;
+use diced_utils;
+use std::convert::{TryInto, Into};
+
+mod utils;
+use utils::with_connection;
+
+static TEST_MESSAGE: &[u8] = &[
+    // "My test message!"
+    0x4d, 0x79, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x21,
+    0x0a,
+];
+
+// This test calls derive with an empty argument vector and with a set of three input values.
+// It then performs the same three derivation steps on the result of the former and compares
+// the result to the result of the latter.
+#[test]
+fn equivalence_test() {
+    with_connection(|device| {
+        let input_values = diced_sample_inputs::get_input_values_vector();
+        let former = device.derive(&[]).expect("Trying to call derive.");
+        let latter = device
+            .derive(&input_values)
+            .expect("Trying to call derive with input values.");
+        let artifacts = diced_utils::ResidentArtifacts::new(
+            former.cdiAttest[..].try_into().unwrap(),
+            former.cdiSeal[..].try_into().unwrap(),
+            &former.bcc.data,
+        )
+        .unwrap();
+
+        let input_values: Vec<diced_utils::InputValues> = input_values
+            .iter()
+            .map(|v| v.into())
+            .collect();
+
+        let artifacts = artifacts
+            .execute_steps(input_values.iter().map(|v| v as &dyn dice::InputValues))
+            .unwrap();
+        let (cdi_attest, cdi_seal, bcc) = artifacts.into_tuple();
+        let from_former = diced_utils::make_bcc_handover(
+            cdi_attest[..].try_into().unwrap(),
+            cdi_seal[..].try_into().unwrap(),
+            &bcc,
+        )
+        .unwrap();
+        // TODO b/204938506 when we have a parser/verifier, check equivalence rather
+        // than bit by bit equality.
+        assert_eq!(latter, from_former);
+        Ok(())
+    })
+}
+
+#[test]
+fn sign_and_verify() {
+    with_connection(|device| {
+        let _signature = device
+            .sign(&[], TEST_MESSAGE)
+            .expect("Trying to call sign.");
+
+        let _bcc = device
+            .getAttestationChain(&[])
+            .expect("Trying to call getAttestationChain.");
+        // TODO b/204938506 check the signature with the bcc when the verifier is available.
+        Ok(())
+    })
+}
diff --git a/security/dice/aidl/vts/functional/utils.rs b/security/dice/aidl/vts/functional/utils.rs
new file mode 100644
index 0000000..4e6708e
--- /dev/null
+++ b/security/dice/aidl/vts/functional/utils.rs
@@ -0,0 +1,53 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use android_hardware_security_dice::aidl::android::hardware::security::dice::IDiceDevice::IDiceDevice;
+use anyhow::Result;
+use binder::Strong;
+use keystore2_vintf::get_aidl_instances;
+use std::sync::Arc;
+
+static DICE_DEVICE_SERVICE_NAME: &str = &"android.hardware.security.dice";
+static DICE_DEVICE_INTERFACE_NAME: &str = &"IDiceDevice";
+
+/// This function iterates through all announced IDiceDevice services and runs the given test
+/// closure against connections to each of them. It also modifies the panic hook to indicate
+/// on which instance the test failed in case the test closure panics.
+pub fn with_connection<R, F>(test: F)
+where
+    F: Fn(&Strong<dyn IDiceDevice>) -> Result<R>,
+{
+    let instances = get_aidl_instances(DICE_DEVICE_SERVICE_NAME, 1, DICE_DEVICE_INTERFACE_NAME);
+    let panic_hook = Arc::new(std::panic::take_hook());
+    for i in instances.into_iter() {
+        let panic_hook_clone = panic_hook.clone();
+        let instance_clone = i.clone();
+        std::panic::set_hook(Box::new(move |v| {
+            println!("While testing instance: \"{}\"", instance_clone);
+            panic_hook_clone(v)
+        }));
+        let connection: Strong<dyn IDiceDevice> = binder::get_interface(&format!(
+            "{}.{}/{}",
+            DICE_DEVICE_SERVICE_NAME, DICE_DEVICE_INTERFACE_NAME, i
+        ))
+        .unwrap();
+        test(&connection).unwrap();
+        drop(std::panic::take_hook());
+    }
+    // Cannot call unwrap here because the panic hook is not Debug.
+    std::panic::set_hook(match Arc::try_unwrap(panic_hook) {
+        Ok(hook) => hook,
+        _ => panic!("Failed to unwrap and reset previous panic hook."),
+    })
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
index fa643fc..dcc22c4 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -49,5 +49,8 @@
   void earlyBootEnded();
   byte[] convertStorageKeyToEphemeral(in byte[] storageKeyBlob);
   android.hardware.security.keymint.KeyCharacteristics[] getKeyCharacteristics(in byte[] keyBlob, in byte[] appId, in byte[] appData);
+  byte[16] getRootOfTrustChallenge();
+  byte[] getRootOfTrust(in byte[16] challenge);
+  void sendRootOfTrust(in byte[] rootOfTrust);
   const int AUTH_TOKEN_MAC_LENGTH = 32;
 }
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 4b63799..da02d54 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -851,4 +851,82 @@
      */
     KeyCharacteristics[] getKeyCharacteristics(
             in byte[] keyBlob, in byte[] appId, in byte[] appData);
+
+    /**
+     * Returns a 16-byte random challenge nonce, used to prove freshness when exchanging root of
+     * trust data.
+     *
+     * This method may only be implemented by StrongBox KeyMint.  TEE KeyMint implementations must
+     * return ErrorCode::UNIMPLEMENTED.  StrongBox KeyMint implementations MAY return UNIMPLEMENTED,
+     * to indicate that they have an alternative mechanism for getting the data.  If the StrongBox
+     * implementation returns UNIMPLEMENTED, the client should not call `getRootofTrust()` or
+     * `sendRootOfTrust()`.
+     */
+    byte[16] getRootOfTrustChallenge();
+
+    /**
+     * Returns the TEE KeyMint Root of Trust data.
+     *
+     * This method is required for TEE KeyMint.  StrongBox KeyMint implementations MUST return
+     * ErrorCode::UNIMPLEMENTED.
+     *
+     * The returned data is an encoded COSE_Mac0 structure, denoted MacedRootOfTrust in the
+     * following CDDL schema.  Note that K_mac is the shared HMAC key used for auth tokens, etc.:
+     *
+     *     MacedRootOfTrust = [               ; COSE_Mac0 (untagged)
+     *         protected: bstr .cbor {
+     *             1 : 5,                     ; Algorithm : HMAC-256
+     *         },
+     *         unprotected : {},
+     *         payload : bstr .cbor RootOfTrust,
+     *         tag : bstr HMAC-256(K_mac, MAC_structure)
+     *     ]
+     *
+     *     MAC_structure = [
+     *         context : "MAC0",
+     *         protected : bstr .cbor {
+     *             1 : 5,                     ; Algorithm : HMAC-256
+     *         },
+     *         external_aad : bstr .size 16   ; Value of challenge argument
+     *         payload : bstr .cbor RootOfTrust,
+     *     ]
+     *
+     *     RootOfTrust = [
+     *         verifiedBootKey : bstr .size 32,
+     *         deviceLocked : bool,
+     *         verifiedBootState : &VerifiedBootState,
+     *         verifiedBootHash : bstr .size 32,
+     *         bootPatchLevel : int,          ; See Tag::BOOT_PATCHLEVEL
+     *     ]
+     *
+     *     VerifiedBootState = (
+     *         Verified : 0,
+     *         SelfSigned : 1,
+     *         Unverified : 2,
+     *         Failed : 3
+     *     )
+     */
+    byte[] getRootOfTrust(in byte[16] challenge);
+
+    /**
+     * Delivers the TEE KeyMint Root of Trust data to StrongBox KeyMint.  See `getRootOfTrust()`
+     * above for specification of the data format and cryptographic security structure.
+     *
+     * The implementation must verify the MAC on the RootOfTrust data.  If it is valid, and if this
+     * is the first time since reboot that StrongBox KeyMint has received this data, it must store
+     * the RoT data for use in key attestation requests, then return ErrorCode::ERROR_OK.
+     *
+     * If the MAC on the Root of Trust data and challenge is incorrect, the implementation must
+     * return ErrorCode::VERIFICATION_FAILED.
+     *
+     * If the RootOfTrust data has already been received since the last boot, the implementation
+     * must validate the data and return ErrorCode::VERIFICATION_FAILED or ErrorCode::ERROR_OK
+     * according to the result, but must not store the data for use in key attestation requests,
+     * even if verification succeeds.  On success, the challenge is invalidated and a new challenge
+     * must be requested before the RootOfTrust data may be sent again.
+     *
+     * This method is optional for StrongBox KeyMint, which MUST return ErrorCode::UNIMPLEMENTED if
+     * not implemented.  TEE KeyMint implementations must return ErrorCode::UNIMPLEMENTED.
+     */
+    void sendRootOfTrust(in byte[] rootOfTrust);
 }
diff --git a/security/keymint/aidl/default/TEST_MAPPING b/security/keymint/aidl/default/TEST_MAPPING
new file mode 100644
index 0000000..2400ccd
--- /dev/null
+++ b/security/keymint/aidl/default/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit" : [
+    {
+      "name" : "vts_treble_vintf_framework_test"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/security/keymint/aidl/default/android.hardware.hardware_keystore.xml b/security/keymint/aidl/default/android.hardware.hardware_keystore.xml
index e5a9345..2ebf1fe 100644
--- a/security/keymint/aidl/default/android.hardware.hardware_keystore.xml
+++ b/security/keymint/aidl/default/android.hardware.hardware_keystore.xml
@@ -14,5 +14,5 @@
      limitations under the License.
 -->
 <permissions>
-  <feature name="android.hardware.hardware_keystore" version="100" />
+  <feature name="android.hardware.hardware_keystore" version="200" />
 </permissions>
diff --git a/security/keymint/aidl/default/android.hardware.security.keymint-service.xml b/security/keymint/aidl/default/android.hardware.security.keymint-service.xml
index 4aa05ef..a4d0302 100644
--- a/security/keymint/aidl/default/android.hardware.security.keymint-service.xml
+++ b/security/keymint/aidl/default/android.hardware.security.keymint-service.xml
@@ -1,10 +1,12 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.security.keymint</name>
+        <version>2</version>
         <fqname>IKeyMintDevice/default</fqname>
     </hal>
     <hal format="aidl">
         <name>android.hardware.security.keymint</name>
+        <version>2</version>
         <fqname>IRemotelyProvisionedComponent/default</fqname>
     </hal>
 </manifest>
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index 91db3c8..ef5b0bd 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -50,10 +50,14 @@
     defaults: [
         "keymint_vts_defaults",
     ],
+    tidy_timeout_srcs: [
+        "KeyMintTest.cpp",
+    ],
     srcs: [
         "AttestKeyTest.cpp",
         "DeviceUniqueAttestationTest.cpp",
         "KeyMintTest.cpp",
+        "SecureElementProvisioningTest.cpp",
     ],
     static_libs: [
         "libkeymint_vts_test_utils",
@@ -69,6 +73,9 @@
     defaults: [
         "keymint_vts_defaults",
     ],
+    tidy_timeout_srcs: [
+        "KeyMintAidlTestBase.cpp",
+    ],
     srcs: [
         "KeyMintAidlTestBase.cpp",
     ],
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index 727c6b7..8a26b3c 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -219,18 +219,22 @@
     AttestationKey attest_key;
     vector<KeyCharacteristics> attest_key_characteristics;
     vector<Certificate> attest_key_cert_chain;
-    ASSERT_EQ(ErrorCode::OK,
-              GenerateKey(AuthorizationSetBuilder()
-                                  .RsaKey(2048, 65537)
-                                  .AttestKey()
-                                  .AttestationChallenge(challenge)
-                                  .AttestationApplicationId(app_id)
-                                  .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                  .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                  .Authorization(TAG_NO_AUTH_REQUIRED)
-                                  .SetDefaultValidity(),
-                          {} /* attestation signing key */, &attest_key.keyBlob,
-                          &attest_key_characteristics, &attest_key_cert_chain));
+    auto result = GenerateKey(AuthorizationSetBuilder()
+                                      .RsaKey(2048, 65537)
+                                      .AttestKey()
+                                      .AttestationChallenge(challenge)
+                                      .AttestationApplicationId(app_id)
+                                      .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                      .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                      .Authorization(TAG_NO_AUTH_REQUIRED)
+                                      .SetDefaultValidity(),
+                              {} /* attestation signing key */, &attest_key.keyBlob,
+                              &attest_key_characteristics, &attest_key_cert_chain);
+    // Strongbox may not support factory provisioned attestation key.
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
+    }
+    ASSERT_EQ(ErrorCode::OK, result);
 
     EXPECT_GT(attest_key_cert_chain.size(), 1);
     verify_subject_and_serial(attest_key_cert_chain[0], serial_int, subject, false);
@@ -319,18 +323,22 @@
             attest_key_opt = attest_key;
         }
 
-        EXPECT_EQ(ErrorCode::OK,
-                  GenerateKey(AuthorizationSetBuilder()
-                                      .RsaKey(2048, 65537)
-                                      .AttestKey()
-                                      .AttestationChallenge("foo")
-                                      .AttestationApplicationId("bar")
-                                      .Authorization(TAG_NO_AUTH_REQUIRED)
-                                      .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                      .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                      .SetDefaultValidity(),
-                              attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
-                              &cert_chain_list[i]));
+        auto result = GenerateKey(AuthorizationSetBuilder()
+                                          .RsaKey(2048, 65537)
+                                          .AttestKey()
+                                          .AttestationChallenge("foo")
+                                          .AttestationApplicationId("bar")
+                                          .Authorization(TAG_NO_AUTH_REQUIRED)
+                                          .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                          .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                          .SetDefaultValidity(),
+                                  attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
+                                  &cert_chain_list[i]);
+        // Strongbox may not support factory provisioned attestation key.
+        if (SecLevel() == SecurityLevel::STRONGBOX) {
+            if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
+        }
+        ASSERT_EQ(ErrorCode::OK, result);
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
@@ -392,18 +400,22 @@
             attest_key_opt = attest_key;
         }
 
-        EXPECT_EQ(ErrorCode::OK,
-                  GenerateKey(AuthorizationSetBuilder()
-                                      .EcdsaKey(EcCurve::P_256)
-                                      .AttestKey()
-                                      .AttestationChallenge("foo")
-                                      .AttestationApplicationId("bar")
-                                      .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                      .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                      .Authorization(TAG_NO_AUTH_REQUIRED)
-                                      .SetDefaultValidity(),
-                              attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
-                              &cert_chain_list[i]));
+        auto result = GenerateKey(AuthorizationSetBuilder()
+                                          .EcdsaKey(EcCurve::P_256)
+                                          .AttestKey()
+                                          .AttestationChallenge("foo")
+                                          .AttestationApplicationId("bar")
+                                          .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                          .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                          .Authorization(TAG_NO_AUTH_REQUIRED)
+                                          .SetDefaultValidity(),
+                                  attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
+                                  &cert_chain_list[i]);
+        // Strongbox may not support factory provisioned attestation key.
+        if (SecLevel() == SecurityLevel::STRONGBOX) {
+            if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
+        }
+        ASSERT_EQ(ErrorCode::OK, result);
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
@@ -484,34 +496,37 @@
             attest_key.keyBlob = key_blob_list[i - 1];
             attest_key_opt = attest_key;
         }
-
+        ErrorCode result;
         if ((i & 0x1) == 1) {
-            EXPECT_EQ(ErrorCode::OK,
-                      GenerateKey(AuthorizationSetBuilder()
-                                          .EcdsaKey(EcCurve::P_256)
-                                          .AttestKey()
-                                          .AttestationChallenge("foo")
-                                          .AttestationApplicationId("bar")
-                                          .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                          .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                          .Authorization(TAG_NO_AUTH_REQUIRED)
-                                          .SetDefaultValidity(),
-                                  attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
-                                  &cert_chain_list[i]));
+            result = GenerateKey(AuthorizationSetBuilder()
+                                         .EcdsaKey(EcCurve::P_256)
+                                         .AttestKey()
+                                         .AttestationChallenge("foo")
+                                         .AttestationApplicationId("bar")
+                                         .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                         .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                         .Authorization(TAG_NO_AUTH_REQUIRED)
+                                         .SetDefaultValidity(),
+                                 attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
+                                 &cert_chain_list[i]);
         } else {
-            EXPECT_EQ(ErrorCode::OK,
-                      GenerateKey(AuthorizationSetBuilder()
-                                          .RsaKey(2048, 65537)
-                                          .AttestKey()
-                                          .AttestationChallenge("foo")
-                                          .AttestationApplicationId("bar")
-                                          .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                          .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                          .Authorization(TAG_NO_AUTH_REQUIRED)
-                                          .SetDefaultValidity(),
-                                  attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
-                                  &cert_chain_list[i]));
+            result = GenerateKey(AuthorizationSetBuilder()
+                                         .RsaKey(2048, 65537)
+                                         .AttestKey()
+                                         .AttestationChallenge("foo")
+                                         .AttestationApplicationId("bar")
+                                         .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                         .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                         .Authorization(TAG_NO_AUTH_REQUIRED)
+                                         .SetDefaultValidity(),
+                                 attest_key_opt, &key_blob_list[i], &attested_key_characteristics,
+                                 &cert_chain_list[i]);
         }
+        // Strongbox may not support factory provisioned attestation key.
+        if (SecLevel() == SecurityLevel::STRONGBOX) {
+            if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
+        }
+        ASSERT_EQ(ErrorCode::OK, result);
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
diff --git a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
index d4bbd69..1dc5df3 100644
--- a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
+++ b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -80,6 +80,7 @@
                                       .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
                                       .Authorization(TAG_INCLUDE_UNIQUE_ID)
                                       .Authorization(TAG_CREATION_DATETIME, 1619621648000)
+                                      .SetDefaultValidity()
                                       .AttestationChallenge("challenge")
                                       .AttestationApplicationId("foo")
                                       .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION),
@@ -109,6 +110,7 @@
                                       .Digest(Digest::SHA_2_256)
                                       .Authorization(TAG_INCLUDE_UNIQUE_ID)
                                       .Authorization(TAG_CREATION_DATETIME, 1619621648000)
+                                      .SetDefaultValidity()
                                       .AttestationChallenge("challenge")
                                       .AttestationApplicationId("foo")
                                       .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION),
@@ -139,6 +141,7 @@
                                       .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
                                       .Authorization(TAG_INCLUDE_UNIQUE_ID)
                                       .Authorization(TAG_CREATION_DATETIME, 1619621648000)
+                                      .SetDefaultValidity()
                                       .AttestationChallenge("challenge")
                                       .AttestationApplicationId("foo")
                                       .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION),
@@ -197,6 +200,7 @@
                                       .Digest(Digest::SHA_2_256)
                                       .Authorization(TAG_INCLUDE_UNIQUE_ID)
                                       .Authorization(TAG_CREATION_DATETIME, 1619621648000)
+                                      .SetDefaultValidity()
                                       .AttestationChallenge("challenge")
                                       .AttestationApplicationId("foo")
                                       .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION),
@@ -264,6 +268,7 @@
                         .Digest(Digest::SHA_2_256)
                         .Authorization(TAG_INCLUDE_UNIQUE_ID)
                         .Authorization(TAG_CREATION_DATETIME, 1619621648000)
+                        .SetDefaultValidity()
                         .AttestationChallenge("challenge")
                         .AttestationApplicationId("foo")
                         .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION);
@@ -336,6 +341,7 @@
                         .Digest(Digest::SHA_2_256)
                         .Authorization(TAG_INCLUDE_UNIQUE_ID)
                         .Authorization(TAG_CREATION_DATETIME, 1619621648000)
+                        .SetDefaultValidity()
                         .AttestationChallenge("challenge")
                         .AttestationApplicationId("foo")
                         .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION);
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 146a527..4ab989b 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -665,6 +665,81 @@
             AuthorizationSetBuilder().Digest(digest).Authorization(TAG_MAC_LENGTH, mac_length));
 }
 
+void KeyMintAidlTestBase::CheckAesIncrementalEncryptOperation(BlockMode block_mode,
+                                                              int message_size) {
+    auto builder = AuthorizationSetBuilder()
+                           .Authorization(TAG_NO_AUTH_REQUIRED)
+                           .AesEncryptionKey(128)
+                           .BlockMode(block_mode)
+                           .Padding(PaddingMode::NONE);
+    if (block_mode == BlockMode::GCM) {
+        builder.Authorization(TAG_MIN_MAC_LENGTH, 128);
+    }
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(builder));
+
+    for (int increment = 1; increment <= message_size; ++increment) {
+        string message(message_size, 'a');
+        auto params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(PaddingMode::NONE);
+        if (block_mode == BlockMode::GCM) {
+            params.Authorization(TAG_MAC_LENGTH, 128) /* for GCM */;
+        }
+
+        AuthorizationSet output_params;
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
+
+        string ciphertext;
+        string to_send;
+        for (size_t i = 0; i < message.size(); i += increment) {
+            EXPECT_EQ(ErrorCode::OK, Update(message.substr(i, increment), &ciphertext));
+        }
+        EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext))
+                << "Error sending " << to_send << " with block mode " << block_mode;
+
+        switch (block_mode) {
+            case BlockMode::GCM:
+                EXPECT_EQ(message.size() + 16, ciphertext.size());
+                break;
+            case BlockMode::CTR:
+                EXPECT_EQ(message.size(), ciphertext.size());
+                break;
+            case BlockMode::CBC:
+            case BlockMode::ECB:
+                EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size());
+                break;
+        }
+
+        auto iv = output_params.GetTagValue(TAG_NONCE);
+        switch (block_mode) {
+            case BlockMode::CBC:
+            case BlockMode::GCM:
+            case BlockMode::CTR:
+                ASSERT_TRUE(iv) << "No IV for block mode " << block_mode;
+                EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv->get().size());
+                params.push_back(TAG_NONCE, iv->get());
+                break;
+
+            case BlockMode::ECB:
+                EXPECT_FALSE(iv) << "ECB mode should not generate IV";
+                break;
+        }
+
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params))
+                << "Decrypt begin() failed for block mode " << block_mode;
+
+        string plaintext;
+        for (size_t i = 0; i < ciphertext.size(); i += increment) {
+            EXPECT_EQ(ErrorCode::OK, Update(ciphertext.substr(i, increment), &plaintext));
+        }
+        ErrorCode error = Finish(to_send, &plaintext);
+        ASSERT_EQ(ErrorCode::OK, error) << "Decryption failed for block mode " << block_mode
+                                        << " and increment " << increment;
+        if (error == ErrorCode::OK) {
+            ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode " << block_mode
+                                          << " and increment " << increment;
+        }
+    }
+}
+
 void KeyMintAidlTestBase::CheckHmacTestVector(const string& key, const string& message,
                                               Digest digest, const string& expected_mac) {
     SCOPED_TRACE("CheckHmacTestVector");
@@ -1228,6 +1303,14 @@
     }
 }
 
+vector<uint64_t> KeyMintAidlTestBase::ValidExponents() {
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        return {65537};
+    } else {
+        return {3, 65537};
+    }
+}
+
 vector<Digest> KeyMintAidlTestBase::ValidDigests(bool withNone, bool withMD5) {
     switch (SecLevel()) {
         case SecurityLevel::SOFTWARE:
@@ -1536,7 +1619,7 @@
         EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED);
     } else {
         EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
-        EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+        EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
                             verified_boot_key.size()));
     }
 
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 27cb99c..e59443c 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -169,6 +169,8 @@
 
     string MacMessage(const string& message, Digest digest, size_t mac_length);
 
+    void CheckAesIncrementalEncryptOperation(BlockMode block_mode, int message_size);
+
     void CheckHmacTestVector(const string& key, const string& message, Digest digest,
                              const string& expected_mac);
 
@@ -253,7 +255,10 @@
                                                      .SetDefaultValidity();
         tagModifier(&rsaBuilder);
         errorCode = GenerateKey(rsaBuilder, &rsaKeyData.blob, &rsaKeyData.characteristics);
-        EXPECT_EQ(expectedReturn, errorCode);
+        if (!(SecLevel() == SecurityLevel::STRONGBOX &&
+              ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED == errorCode)) {
+            EXPECT_EQ(expectedReturn, errorCode);
+        }
 
         /* ECDSA */
         KeyData ecdsaKeyData;
@@ -265,7 +270,10 @@
                                                        .SetDefaultValidity();
         tagModifier(&ecdsaBuilder);
         errorCode = GenerateKey(ecdsaBuilder, &ecdsaKeyData.blob, &ecdsaKeyData.characteristics);
-        EXPECT_EQ(expectedReturn, errorCode);
+        if (!(SecLevel() == SecurityLevel::STRONGBOX &&
+              ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED == errorCode)) {
+            EXPECT_EQ(expectedReturn, errorCode);
+        }
         return {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData};
     }
     bool IsSecure() const { return securityLevel_ != SecurityLevel::SOFTWARE; }
@@ -282,6 +290,7 @@
     vector<EcCurve> InvalidCurves();
 
     vector<Digest> ValidDigests(bool withNone, bool withMD5);
+    vector<uint64_t> ValidExponents();
 
     static vector<string> build_params() {
         auto params = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 7357ac7..056d83a 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -1018,6 +1018,37 @@
 }
 
 /*
+ * NewKeyGenerationTest.RsaWithMissingValidity
+ *
+ * Verifies that keymint returns an error while generating asymmetric key
+ * without providing NOT_BEFORE and NOT_AFTER parameters.
+ */
+TEST_P(NewKeyGenerationTest, RsaWithMissingValidity) {
+    // Per RFC 5280 4.1.2.5, an undefined expiration (not-after) field should be set to
+    // GeneralizedTime 999912312359559, which is 253402300799000 ms from Jan 1, 1970.
+    constexpr uint64_t kUndefinedExpirationDateTime = 253402300799000;
+
+    vector<uint8_t> key_blob;
+    vector<KeyCharacteristics> key_characteristics;
+    ASSERT_EQ(ErrorCode::MISSING_NOT_BEFORE,
+              GenerateKey(AuthorizationSetBuilder()
+                                  .RsaSigningKey(2048, 65537)
+                                  .Digest(Digest::NONE)
+                                  .Padding(PaddingMode::NONE)
+                                  .Authorization(TAG_CERTIFICATE_NOT_AFTER,
+                                                 kUndefinedExpirationDateTime),
+                          &key_blob, &key_characteristics));
+
+    ASSERT_EQ(ErrorCode::MISSING_NOT_AFTER,
+              GenerateKey(AuthorizationSetBuilder()
+                                  .RsaSigningKey(2048, 65537)
+                                  .Digest(Digest::NONE)
+                                  .Padding(PaddingMode::NONE)
+                                  .Authorization(TAG_CERTIFICATE_NOT_BEFORE, 0),
+                          &key_blob, &key_characteristics));
+}
+
+/*
  * NewKeyGenerationTest.RsaWithAttestation
  *
  * Verifies that keymint can generate all required RSA key sizes with attestation, and that the
@@ -1036,18 +1067,21 @@
     for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
         vector<uint8_t> key_blob;
         vector<KeyCharacteristics> key_characteristics;
-        ASSERT_EQ(ErrorCode::OK,
-                  GenerateKey(AuthorizationSetBuilder()
-                                      .RsaSigningKey(key_size, 65537)
-                                      .Digest(Digest::NONE)
-                                      .Padding(PaddingMode::NONE)
-                                      .AttestationChallenge(challenge)
-                                      .AttestationApplicationId(app_id)
-                                      .Authorization(TAG_NO_AUTH_REQUIRED)
-                                      .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                      .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                      .SetDefaultValidity(),
-                              &key_blob, &key_characteristics));
+        auto result = GenerateKey(AuthorizationSetBuilder()
+                                          .RsaSigningKey(key_size, 65537)
+                                          .Digest(Digest::NONE)
+                                          .Padding(PaddingMode::NONE)
+                                          .AttestationChallenge(challenge)
+                                          .AttestationApplicationId(app_id)
+                                          .Authorization(TAG_NO_AUTH_REQUIRED)
+                                          .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                          .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                          .SetDefaultValidity(),
+                                  &key_blob, &key_characteristics);
+        // Strongbox may not support factory provisioned attestation key.
+        if (SecLevel() == SecurityLevel::STRONGBOX) {
+            if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
+        }
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
@@ -1169,17 +1203,21 @@
 
     vector<uint8_t> key_blob;
     vector<KeyCharacteristics> key_characteristics;
-    ASSERT_EQ(ErrorCode::OK,
-              GenerateKey(AuthorizationSetBuilder()
-                                  .RsaEncryptionKey(key_size, 65537)
-                                  .Padding(PaddingMode::NONE)
-                                  .AttestationChallenge(challenge)
-                                  .AttestationApplicationId(app_id)
-                                  .Authorization(TAG_NO_AUTH_REQUIRED)
-                                  .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                  .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                  .SetDefaultValidity(),
-                          &key_blob, &key_characteristics));
+    auto result = GenerateKey(AuthorizationSetBuilder()
+                                      .RsaEncryptionKey(key_size, 65537)
+                                      .Padding(PaddingMode::NONE)
+                                      .AttestationChallenge(challenge)
+                                      .AttestationApplicationId(app_id)
+                                      .Authorization(TAG_NO_AUTH_REQUIRED)
+                                      .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                      .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                      .SetDefaultValidity(),
+                              &key_blob, &key_characteristics);
+    // Strongbox may not support factory provisioned attestation key.
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
+    }
+    ASSERT_EQ(ErrorCode::OK, result);
 
     ASSERT_GT(key_blob.size(), 0U);
     AuthorizationSet auths;
@@ -1281,15 +1319,19 @@
     vector<uint8_t> key_blob;
     vector<KeyCharacteristics> key_characteristics;
 
-    ASSERT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING,
-              GenerateKey(AuthorizationSetBuilder()
-                                  .RsaSigningKey(2048, 65537)
-                                  .Digest(Digest::NONE)
-                                  .Padding(PaddingMode::NONE)
-                                  .AttestationChallenge(challenge)
-                                  .Authorization(TAG_NO_AUTH_REQUIRED)
-                                  .SetDefaultValidity(),
-                          &key_blob, &key_characteristics));
+    auto result = GenerateKey(AuthorizationSetBuilder()
+                                      .RsaSigningKey(2048, 65537)
+                                      .Digest(Digest::NONE)
+                                      .Padding(PaddingMode::NONE)
+                                      .AttestationChallenge(challenge)
+                                      .Authorization(TAG_NO_AUTH_REQUIRED)
+                                      .SetDefaultValidity(),
+                              &key_blob, &key_characteristics);
+    // Strongbox may not support factory provisioned attestation key.
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
+    }
+    ASSERT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING, result);
 }
 
 /*
@@ -1399,19 +1441,23 @@
     for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
         vector<uint8_t> key_blob;
         vector<KeyCharacteristics> key_characteristics;
-        ASSERT_EQ(ErrorCode::OK,
-                  GenerateKey(AuthorizationSetBuilder()
-                                      .RsaSigningKey(key_size, 65537)
-                                      .Digest(Digest::NONE)
-                                      .Padding(PaddingMode::NONE)
-                                      .AttestationChallenge(challenge)
-                                      .AttestationApplicationId(app_id)
-                                      .Authorization(TAG_NO_AUTH_REQUIRED)
-                                      .Authorization(TAG_USAGE_COUNT_LIMIT, 1)
-                                      .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                      .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                      .SetDefaultValidity(),
-                              &key_blob, &key_characteristics));
+        auto result = GenerateKey(AuthorizationSetBuilder()
+                                          .RsaSigningKey(key_size, 65537)
+                                          .Digest(Digest::NONE)
+                                          .Padding(PaddingMode::NONE)
+                                          .AttestationChallenge(challenge)
+                                          .AttestationApplicationId(app_id)
+                                          .Authorization(TAG_NO_AUTH_REQUIRED)
+                                          .Authorization(TAG_USAGE_COUNT_LIMIT, 1)
+                                          .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                          .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                          .SetDefaultValidity(),
+                                  &key_blob, &key_characteristics);
+        // Strongbox may not support factory provisioned attestation key.
+        if (SecLevel() == SecurityLevel::STRONGBOX) {
+            if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
+        }
+        ASSERT_EQ(ErrorCode::OK, result);
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
@@ -1583,6 +1629,35 @@
 }
 
 /*
+ * NewKeyGenerationTest.EcdsaWithMissingValidity
+ *
+ * Verifies that keymint returns an error while generating asymmetric key
+ * without providing NOT_BEFORE and NOT_AFTER parameters.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaWithMissingValidity) {
+    // Per RFC 5280 4.1.2.5, an undefined expiration (not-after) field should be set to
+    // GeneralizedTime 999912312359559, which is 253402300799000 ms from Jan 1, 1970.
+    constexpr uint64_t kUndefinedExpirationDateTime = 253402300799000;
+
+    vector<uint8_t> key_blob;
+    vector<KeyCharacteristics> key_characteristics;
+    ASSERT_EQ(ErrorCode::MISSING_NOT_BEFORE,
+              GenerateKey(AuthorizationSetBuilder()
+                                  .EcdsaSigningKey(EcCurve::P_256)
+                                  .Digest(Digest::NONE)
+                                  .Authorization(TAG_CERTIFICATE_NOT_AFTER,
+                                                 kUndefinedExpirationDateTime),
+                          &key_blob, &key_characteristics));
+
+    ASSERT_EQ(ErrorCode::MISSING_NOT_AFTER,
+              GenerateKey(AuthorizationSetBuilder()
+                                  .EcdsaSigningKey(EcCurve::P_256)
+                                  .Digest(Digest::NONE)
+                                  .Authorization(TAG_CERTIFICATE_NOT_BEFORE, 0),
+                          &key_blob, &key_characteristics));
+}
+
+/*
  * NewKeyGenerationTest.EcdsaAttestation
  *
  * Verifies that for all Ecdsa key sizes, if challenge and app id is provided,
@@ -1601,17 +1676,21 @@
     for (auto curve : ValidCurves()) {
         vector<uint8_t> key_blob;
         vector<KeyCharacteristics> key_characteristics;
-        ASSERT_EQ(ErrorCode::OK,
-                  GenerateKey(AuthorizationSetBuilder()
-                                      .Authorization(TAG_NO_AUTH_REQUIRED)
-                                      .EcdsaSigningKey(curve)
-                                      .Digest(Digest::NONE)
-                                      .AttestationChallenge(challenge)
-                                      .AttestationApplicationId(app_id)
-                                      .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
-                                      .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
-                                      .SetDefaultValidity(),
-                              &key_blob, &key_characteristics));
+        auto result = GenerateKey(AuthorizationSetBuilder()
+                                          .Authorization(TAG_NO_AUTH_REQUIRED)
+                                          .EcdsaSigningKey(curve)
+                                          .Digest(Digest::NONE)
+                                          .AttestationChallenge(challenge)
+                                          .AttestationApplicationId(app_id)
+                                          .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                                          .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                                          .SetDefaultValidity(),
+                                  &key_blob, &key_characteristics);
+        // Strongbox may not support factory provisioned attestation key.
+        if (SecLevel() == SecurityLevel::STRONGBOX) {
+            if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
+        }
+        ASSERT_EQ(ErrorCode::OK, result);
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
         CheckCharacteristics(key_blob, key_characteristics);
@@ -1745,6 +1824,10 @@
             // Tag not required to be supported by all KeyMint implementations.
             continue;
         }
+        // Strongbox may not support factory provisioned attestation key.
+        if (SecLevel() == SecurityLevel::STRONGBOX) {
+            if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
+        }
         ASSERT_EQ(result, ErrorCode::OK);
         ASSERT_GT(key_blob.size(), 0U);
 
@@ -1840,6 +1923,10 @@
         AuthorizationSetBuilder builder = base_builder;
         builder.push_back(tag);
         auto result = GenerateKey(builder, &key_blob, &key_characteristics);
+        // Strongbox may not support factory provisioned attestation key.
+        if (SecLevel() == SecurityLevel::STRONGBOX) {
+            if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
+        }
         if (result == ErrorCode::CANNOT_ATTEST_IDS) {
             // Device ID attestation is optional; KeyMint may not support it at all.
             continue;
@@ -1997,6 +2084,10 @@
                                       .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
                                       .SetDefaultValidity(),
                               &key_blob, &key_characteristics);
+    // Strongbox may not support factory provisioned attestation key.
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
+    }
     ASSERT_EQ(result, ErrorCode::OK);
     ASSERT_GT(key_blob.size(), 0U);
 
@@ -2076,13 +2167,17 @@
     vector<uint8_t> key_blob;
     vector<KeyCharacteristics> key_characteristics;
 
-    ASSERT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING,
-              GenerateKey(AuthorizationSetBuilder()
-                                  .EcdsaSigningKey(EcCurve::P_256)
-                                  .Digest(Digest::NONE)
-                                  .AttestationChallenge(challenge)
-                                  .SetDefaultValidity(),
-                          &key_blob, &key_characteristics));
+    auto result = GenerateKey(AuthorizationSetBuilder()
+                                      .EcdsaSigningKey(EcCurve::P_256)
+                                      .Digest(Digest::NONE)
+                                      .AttestationChallenge(challenge)
+                                      .SetDefaultValidity(),
+                              &key_blob, &key_characteristics);
+    // Strongbox may not support factory provisioned attestation key.
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
+    }
+    ASSERT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING, result);
 }
 
 /*
@@ -2139,14 +2234,19 @@
         const string app_id(length, 'a');
         vector<uint8_t> key_blob;
         vector<KeyCharacteristics> key_characteristics;
-        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                     .Authorization(TAG_NO_AUTH_REQUIRED)
-                                                     .EcdsaSigningKey(EcCurve::P_256)
-                                                     .Digest(Digest::NONE)
-                                                     .AttestationChallenge(challenge)
-                                                     .AttestationApplicationId(app_id)
-                                                     .SetDefaultValidity(),
-                                             &key_blob, &key_characteristics));
+        auto result = GenerateKey(AuthorizationSetBuilder()
+                                          .Authorization(TAG_NO_AUTH_REQUIRED)
+                                          .EcdsaSigningKey(EcCurve::P_256)
+                                          .Digest(Digest::NONE)
+                                          .AttestationChallenge(challenge)
+                                          .AttestationApplicationId(app_id)
+                                          .SetDefaultValidity(),
+                                  &key_blob, &key_characteristics);
+        // Strongbox may not support factory provisioned attestation key.
+        if (SecLevel() == SecurityLevel::STRONGBOX) {
+            if (result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) return;
+        }
+        ASSERT_EQ(ErrorCode::OK, result);
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
         CheckCharacteristics(key_blob, key_characteristics);
@@ -4646,7 +4746,7 @@
  * Verifies that raw RSA decryption works.
  */
 TEST_P(EncryptionOperationsTest, RsaNoPaddingSuccess) {
-    for (uint64_t exponent : {3, 65537}) {
+    for (uint64_t exponent : ValidExponents()) {
         ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                                      .Authorization(TAG_NO_AUTH_REQUIRED)
                                                      .RsaEncryptionKey(2048, exponent)
@@ -5341,89 +5441,39 @@
 }
 
 /*
- * EncryptionOperationsTest.AesIncremental
+ * EncryptionOperationsTest.AesEcbIncremental
  *
- * Verifies that AES works, all modes, when provided data in various size increments.
+ * Verifies that AES works for ECB block mode, when provided data in various size increments.
  */
-TEST_P(EncryptionOperationsTest, AesIncremental) {
-    auto block_modes = {
-            BlockMode::ECB,
-            BlockMode::CBC,
-            BlockMode::CTR,
-            BlockMode::GCM,
-    };
+TEST_P(EncryptionOperationsTest, AesEcbIncremental) {
+    CheckAesIncrementalEncryptOperation(BlockMode::ECB, 240);
+}
 
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
-                                                 .AesEncryptionKey(128)
-                                                 .BlockMode(block_modes)
-                                                 .Padding(PaddingMode::NONE)
-                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+/*
+ * EncryptionOperationsTest.AesCbcIncremental
+ *
+ * Verifies that AES works for CBC block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesCbcIncremental) {
+    CheckAesIncrementalEncryptOperation(BlockMode::CBC, 240);
+}
 
-    for (int increment = 1; increment <= 240; ++increment) {
-        for (auto block_mode : block_modes) {
-            string message(240, 'a');
-            auto params =
-                    AuthorizationSetBuilder().BlockMode(block_mode).Padding(PaddingMode::NONE);
-            if (block_mode == BlockMode::GCM) {
-                params.Authorization(TAG_MAC_LENGTH, 128) /* for GCM */;
-            }
+/*
+ * EncryptionOperationsTest.AesCtrIncremental
+ *
+ * Verifies that AES works for CTR block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesCtrIncremental) {
+    CheckAesIncrementalEncryptOperation(BlockMode::CTR, 240);
+}
 
-            AuthorizationSet output_params;
-            EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
-
-            string ciphertext;
-            string to_send;
-            for (size_t i = 0; i < message.size(); i += increment) {
-                EXPECT_EQ(ErrorCode::OK, Update(message.substr(i, increment), &ciphertext));
-            }
-            EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext))
-                    << "Error sending " << to_send << " with block mode " << block_mode;
-
-            switch (block_mode) {
-                case BlockMode::GCM:
-                    EXPECT_EQ(message.size() + 16, ciphertext.size());
-                    break;
-                case BlockMode::CTR:
-                    EXPECT_EQ(message.size(), ciphertext.size());
-                    break;
-                case BlockMode::CBC:
-                case BlockMode::ECB:
-                    EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size());
-                    break;
-            }
-
-            auto iv = output_params.GetTagValue(TAG_NONCE);
-            switch (block_mode) {
-                case BlockMode::CBC:
-                case BlockMode::GCM:
-                case BlockMode::CTR:
-                    ASSERT_TRUE(iv) << "No IV for block mode " << block_mode;
-                    EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv->get().size());
-                    params.push_back(TAG_NONCE, iv->get());
-                    break;
-
-                case BlockMode::ECB:
-                    EXPECT_FALSE(iv) << "ECB mode should not generate IV";
-                    break;
-            }
-
-            EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params))
-                    << "Decrypt begin() failed for block mode " << block_mode;
-
-            string plaintext;
-            for (size_t i = 0; i < ciphertext.size(); i += increment) {
-                EXPECT_EQ(ErrorCode::OK, Update(ciphertext.substr(i, increment), &plaintext));
-            }
-            ErrorCode error = Finish(to_send, &plaintext);
-            ASSERT_EQ(ErrorCode::OK, error) << "Decryption failed for block mode " << block_mode
-                                            << " and increment " << increment;
-            if (error == ErrorCode::OK) {
-                ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode "
-                                              << block_mode << " and increment " << increment;
-            }
-        }
-    }
+/*
+ * EncryptionOperationsTest.AesGcmIncremental
+ *
+ * Verifies that AES works for GCM block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmIncremental) {
+    CheckAesIncrementalEncryptOperation(BlockMode::GCM, 240);
 }
 
 struct AesCtrSp80038aTestVector {
@@ -7654,14 +7704,23 @@
             });
 
     for (const auto& keyData : {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData}) {
+        // Strongbox may not support factory attestation. Key creation might fail with
+        // ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED
+        if (SecLevel() == SecurityLevel::STRONGBOX && keyData.blob.size() == 0U) {
+            continue;
+        }
         ASSERT_GT(keyData.blob.size(), 0U);
         AuthorizationSet crypto_params = SecLevelAuthorizations(keyData.characteristics);
         EXPECT_TRUE(crypto_params.Contains(TAG_EARLY_BOOT_ONLY)) << crypto_params;
     }
     CheckedDeleteKey(&aesKeyData.blob);
     CheckedDeleteKey(&hmacKeyData.blob);
-    CheckedDeleteKey(&rsaKeyData.blob);
-    CheckedDeleteKey(&ecdsaKeyData.blob);
+    if (rsaKeyData.blob.size() != 0U) {
+        CheckedDeleteKey(&rsaKeyData.blob);
+    }
+    if (ecdsaKeyData.blob.size() != 0U) {
+        CheckedDeleteKey(&ecdsaKeyData.blob);
+    }
 }
 
 /*
diff --git a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
new file mode 100644
index 0000000..6f13867
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "keymint_2_se_provisioning_test"
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+
+#include <cppbor_parse.h>
+#include <keymaster/cppcose/cppcose.h>
+#include <keymint_support/key_param_output.h>
+
+#include "KeyMintAidlTestBase.h"
+
+namespace aidl::android::hardware::security::keymint::test {
+
+using std::array;
+using std::map;
+using std::shared_ptr;
+using std::vector;
+
+class SecureElementProvisioningTest : public testing::Test {
+  protected:
+    static void SetUpTestSuite() {
+        auto params = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
+        for (auto& param : params) {
+            ASSERT_TRUE(AServiceManager_isDeclared(param.c_str()))
+                    << "IKeyMintDevice instance " << param << " found but not declared.";
+            ::ndk::SpAIBinder binder(AServiceManager_waitForService(param.c_str()));
+            auto keymint = IKeyMintDevice::fromBinder(binder);
+            ASSERT_NE(keymint, nullptr) << "Failed to get IKeyMintDevice instance " << param;
+
+            KeyMintHardwareInfo info;
+            ASSERT_TRUE(keymint->getHardwareInfo(&info).isOk());
+            ASSERT_EQ(keymints_.count(info.securityLevel), 0)
+                    << "There must be exactly one IKeyMintDevice with security level "
+                    << info.securityLevel;
+
+            keymints_[info.securityLevel] = std::move(keymint);
+        }
+    }
+
+    static map<SecurityLevel, shared_ptr<IKeyMintDevice>> keymints_;
+};
+
+map<SecurityLevel, shared_ptr<IKeyMintDevice>> SecureElementProvisioningTest::keymints_;
+
+TEST_F(SecureElementProvisioningTest, ValidConfigurations) {
+    if (keymints_.empty()) {
+        GTEST_SKIP() << "Test not applicable to device with no KeyMint devices";
+    }
+    // TEE is required
+    ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
+    // StrongBox is optional
+    ASSERT_LE(keymints_.count(SecurityLevel::STRONGBOX), 1);
+}
+
+TEST_F(SecureElementProvisioningTest, TeeOnly) {
+    if (keymints_.empty()) {
+        GTEST_SKIP() << "Test not applicable to device with no KeyMint devices";
+    }
+    ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
+    auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
+    ASSERT_NE(tee, nullptr);
+
+    array<uint8_t, 16> challenge1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    array<uint8_t, 16> challenge2 = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+    vector<uint8_t> rootOfTrust1;
+    Status result = tee->getRootOfTrust(challenge1, &rootOfTrust1);
+
+    // TODO: Remove the next line to require TEEs to succeed.
+    if (!result.isOk()) return;
+
+    ASSERT_TRUE(result.isOk());
+
+    // TODO:  Parse and validate rootOfTrust1 here
+
+    vector<uint8_t> rootOfTrust2;
+    result = tee->getRootOfTrust(challenge2, &rootOfTrust2);
+    ASSERT_TRUE(result.isOk());
+
+    // TODO:  Parse and validate rootOfTrust2 here
+
+    ASSERT_NE(rootOfTrust1, rootOfTrust2);
+
+    vector<uint8_t> rootOfTrust3;
+    result = tee->getRootOfTrust(challenge1, &rootOfTrust3);
+    ASSERT_TRUE(result.isOk());
+
+    ASSERT_EQ(rootOfTrust1, rootOfTrust3);
+
+    // TODO:  Parse and validate rootOfTrust3 here
+}
+
+TEST_F(SecureElementProvisioningTest, TeeDoesNotImplementStrongBoxMethods) {
+    if (keymints_.empty()) {
+        GTEST_SKIP() << "Test not applicable to device with no KeyMint devices";
+    }
+    ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
+    auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
+    ASSERT_NE(tee, nullptr);
+
+    array<uint8_t, 16> challenge;
+    Status result = tee->getRootOfTrustChallenge(&challenge);
+    ASSERT_FALSE(result.isOk());
+    ASSERT_EQ(result.getExceptionCode(), EX_SERVICE_SPECIFIC);
+    ASSERT_EQ(static_cast<ErrorCode>(result.getServiceSpecificError()), ErrorCode::UNIMPLEMENTED);
+
+    result = tee->sendRootOfTrust({});
+    ASSERT_FALSE(result.isOk());
+    ASSERT_EQ(result.getExceptionCode(), EX_SERVICE_SPECIFIC);
+    ASSERT_EQ(static_cast<ErrorCode>(result.getServiceSpecificError()), ErrorCode::UNIMPLEMENTED);
+}
+
+TEST_F(SecureElementProvisioningTest, StrongBoxDoesNotImplementTeeMethods) {
+    if (keymints_.count(SecurityLevel::STRONGBOX) == 0) {
+        // Need a StrongBox to provision.
+        GTEST_SKIP() << "Test not applicable to device with no StrongBox KeyMint device";
+    }
+
+    auto sb = keymints_.find(SecurityLevel::STRONGBOX)->second;
+    ASSERT_NE(sb, nullptr);
+
+    vector<uint8_t> rootOfTrust;
+    Status result = sb->getRootOfTrust({}, &rootOfTrust);
+    ASSERT_FALSE(result.isOk());
+    ASSERT_EQ(result.getExceptionCode(), EX_SERVICE_SPECIFIC);
+    ASSERT_EQ(static_cast<ErrorCode>(result.getServiceSpecificError()), ErrorCode::UNIMPLEMENTED);
+}
+
+TEST_F(SecureElementProvisioningTest, UnimplementedTest) {
+    if (keymints_.count(SecurityLevel::STRONGBOX) == 0) {
+        // Need a StrongBox to provision.
+        GTEST_SKIP() << "Test not applicable to device with no StrongBox KeyMint device";
+    }
+
+    ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
+    auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
+    ASSERT_NE(tee, nullptr);
+
+    ASSERT_EQ(keymints_.count(SecurityLevel::STRONGBOX), 1);
+    auto sb = keymints_.find(SecurityLevel::STRONGBOX)->second;
+    ASSERT_NE(sb, nullptr);
+
+    array<uint8_t, 16> challenge;
+    Status result = sb->getRootOfTrustChallenge(&challenge);
+    if (!result.isOk()) {
+        // Strongbox does not have to implement this feature if it has uses an alternative mechanism
+        // to provision the root of trust.  In that case it MUST return UNIMPLEMENTED, both from
+        // getRootOfTrustChallenge() and from sendRootOfTrust().
+        ASSERT_EQ(result.getExceptionCode(), EX_SERVICE_SPECIFIC);
+        ASSERT_EQ(static_cast<ErrorCode>(result.getServiceSpecificError()),
+                  ErrorCode::UNIMPLEMENTED);
+
+        result = sb->sendRootOfTrust({});
+        ASSERT_EQ(result.getExceptionCode(), EX_SERVICE_SPECIFIC);
+        ASSERT_EQ(static_cast<ErrorCode>(result.getServiceSpecificError()),
+                  ErrorCode::UNIMPLEMENTED);
+
+        SUCCEED() << "This Strongbox implementation does not use late root of trust delivery.";
+        return;
+    }
+}
+
+TEST_F(SecureElementProvisioningTest, ChallengeQualityTest) {
+    if (keymints_.count(SecurityLevel::STRONGBOX) == 0) {
+        // Need a StrongBox to provision.
+        GTEST_SKIP() << "Test not applicable to device with no StrongBox KeyMint device";
+    }
+
+    ASSERT_EQ(keymints_.count(SecurityLevel::STRONGBOX), 1);
+    auto sb = keymints_.find(SecurityLevel::STRONGBOX)->second;
+    ASSERT_NE(sb, nullptr);
+
+    array<uint8_t, 16> challenge1;
+    Status result = sb->getRootOfTrustChallenge(&challenge1);
+    if (!result.isOk()) return;
+
+    array<uint8_t, 16> challenge2;
+    result = sb->getRootOfTrustChallenge(&challenge2);
+    ASSERT_TRUE(result.isOk());
+    ASSERT_NE(challenge1, challenge2);
+
+    // TODO: When we add entropy testing in other relevant places in these tests, add it here, too,
+    // to verify that challenges appear to have adequate entropy.
+}
+
+TEST_F(SecureElementProvisioningTest, ProvisioningTest) {
+    if (keymints_.count(SecurityLevel::STRONGBOX) == 0) {
+        // Need a StrongBox to provision.
+        GTEST_SKIP() << "Test not applicable to device with no StrongBox KeyMint device";
+    }
+
+    ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
+    auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
+    ASSERT_NE(tee, nullptr);
+
+    ASSERT_EQ(keymints_.count(SecurityLevel::STRONGBOX), 1);
+    auto sb = keymints_.find(SecurityLevel::STRONGBOX)->second;
+    ASSERT_NE(sb, nullptr);
+
+    array<uint8_t, 16> challenge;
+    Status result = sb->getRootOfTrustChallenge(&challenge);
+    if (!result.isOk()) return;
+
+    vector<uint8_t> rootOfTrust;
+    result = tee->getRootOfTrust(challenge, &rootOfTrust);
+    ASSERT_TRUE(result.isOk());
+
+    // TODO: Verify COSE_Mac0 structure and content here.
+
+    result = sb->sendRootOfTrust(rootOfTrust);
+    ASSERT_TRUE(result.isOk());
+
+    // Sending again must fail, because a new challenge is required.
+    result = sb->sendRootOfTrust(rootOfTrust);
+    ASSERT_FALSE(result.isOk());
+}
+
+TEST_F(SecureElementProvisioningTest, InvalidProvisioningTest) {
+    if (keymints_.count(SecurityLevel::STRONGBOX) == 0) {
+        // Need a StrongBox to provision.
+        GTEST_SKIP() << "Test not applicable to device with no StrongBox KeyMint device";
+    }
+
+    ASSERT_EQ(keymints_.count(SecurityLevel::TRUSTED_ENVIRONMENT), 1);
+    auto tee = keymints_.find(SecurityLevel::TRUSTED_ENVIRONMENT)->second;
+    ASSERT_NE(tee, nullptr);
+
+    ASSERT_EQ(keymints_.count(SecurityLevel::STRONGBOX), 1);
+    auto sb = keymints_.find(SecurityLevel::STRONGBOX)->second;
+    ASSERT_NE(sb, nullptr);
+
+    array<uint8_t, 16> challenge;
+    Status result = sb->getRootOfTrustChallenge(&challenge);
+    if (!result.isOk()) return;
+
+    result = sb->sendRootOfTrust({});
+    ASSERT_FALSE(result.isOk());
+    ASSERT_EQ(result.getExceptionCode(), EX_SERVICE_SPECIFIC);
+    ASSERT_EQ(static_cast<ErrorCode>(result.getServiceSpecificError()),
+              ErrorCode::VERIFICATION_FAILED);
+
+    vector<uint8_t> rootOfTrust;
+    result = tee->getRootOfTrust(challenge, &rootOfTrust);
+    ASSERT_TRUE(result.isOk());
+
+    vector<uint8_t> corruptedRootOfTrust = rootOfTrust;
+    corruptedRootOfTrust[corruptedRootOfTrust.size() / 2]++;
+    result = sb->sendRootOfTrust(corruptedRootOfTrust);
+    ASSERT_FALSE(result.isOk());
+    ASSERT_EQ(result.getExceptionCode(), EX_SERVICE_SPECIFIC);
+    ASSERT_EQ(static_cast<ErrorCode>(result.getServiceSpecificError()),
+              ErrorCode::VERIFICATION_FAILED);
+
+    // Now try the correct RoT
+    result = sb->sendRootOfTrust(rootOfTrust);
+    ASSERT_TRUE(result.isOk());
+}
+
+}  // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index e2d75ce..4341aa1 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -185,6 +185,7 @@
             provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
         }
         ASSERT_NE(provisionable_, nullptr);
+        ASSERT_TRUE(provisionable_->getHardwareInfo(&rpcHardwareInfo).isOk());
     }
 
     static vector<string> build_params() {
@@ -194,6 +195,7 @@
 
   protected:
     std::shared_ptr<IRemotelyProvisionedComponent> provisionable_;
+    RpcHardwareInfo rpcHardwareInfo;
 };
 
 /**
@@ -357,12 +359,11 @@
 class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
   protected:
     CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(32)) {
-        generateTestEekChain(3);
     }
 
     void generateTestEekChain(size_t eekLength) {
-        auto chain = generateEekChain(eekLength, eekId_);
-        EXPECT_TRUE(chain) << chain.message();
+        auto chain = generateEekChain(rpcHardwareInfo.supportedEekCurve, eekLength, eekId_);
+        ASSERT_TRUE(chain) << chain.message();
         if (chain) testEekChain_ = chain.moveValue();
         testEekLength_ = eekLength;
     }
@@ -382,6 +383,17 @@
         }
     }
 
+    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) {
@@ -394,9 +406,7 @@
         ASSERT_TRUE(senderPubkey) << senderPubkey.message();
         EXPECT_EQ(senderPubkey->second, eekId_);
 
-        auto sessionKey =
-                x25519_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
-                                      senderPubkey->first, false /* senderIsA */);
+        auto sessionKey = getSessionKey(senderPubkey);
         ASSERT_TRUE(sessionKey) << sessionKey.message();
 
         auto protectedDataPayload =
@@ -406,7 +416,8 @@
         auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
         ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
         ASSERT_TRUE(parsedPayload->asArray());
-        EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
+        // Strongbox may contain additional certificate chain.
+        EXPECT_LE(parsedPayload->asArray()->size(), 3U);
 
         auto& signedMac = parsedPayload->asArray()->get(0);
         auto& bcc = parsedPayload->asArray()->get(1);
@@ -566,6 +577,7 @@
     bytevec keysToSignMac;
     DeviceInfo deviceInfo;
     ProtectedData protectedData;
+    generateTestEekChain(3);
     auto status = provisionable_->generateCertificateRequest(
             testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
@@ -605,8 +617,8 @@
     DeviceInfo deviceInfo;
     ProtectedData protectedData;
     auto status = provisionable_->generateCertificateRequest(
-            testMode, {} /* keysToSign */, getProdEekChain(), challenge_, &deviceInfo,
-            &protectedData, &keysToSignMac);
+            testMode, {} /* keysToSign */, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
+            challenge_, &deviceInfo, &protectedData, &keysToSignMac);
     EXPECT_TRUE(status.isOk());
 }
 
@@ -646,8 +658,8 @@
     DeviceInfo deviceInfo;
     ProtectedData protectedData;
     auto status = provisionable_->generateCertificateRequest(
-            testMode, keysToSign_, getProdEekChain(), challenge_, &deviceInfo, &protectedData,
-            &keysToSignMac);
+            testMode, keysToSign_, getProdEekChain(rpcHardwareInfo.supportedEekCurve), challenge_,
+            &deviceInfo, &protectedData, &keysToSignMac);
     EXPECT_TRUE(status.isOk());
 }
 
@@ -657,11 +669,14 @@
 TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_testMode) {
     bool testMode = true;
     generateKeys(testMode, 1 /* numKeys */);
-    MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
+    auto result = corrupt_maced_key(keysToSign_[0]);
+    ASSERT_TRUE(result) << result.moveMessage();
+    MacedPublicKey keyWithCorruptMac = result.moveValue();
 
     bytevec keysToSignMac;
     DeviceInfo deviceInfo;
     ProtectedData protectedData;
+    generateTestEekChain(3);
     auto status = provisionable_->generateCertificateRequest(
             testMode, {keyWithCorruptMac}, testEekChain_.chain, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
@@ -675,14 +690,16 @@
 TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_prodMode) {
     bool testMode = false;
     generateKeys(testMode, 1 /* numKeys */);
-    MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
+    auto result = corrupt_maced_key(keysToSign_[0]);
+    ASSERT_TRUE(result) << result.moveMessage();
+    MacedPublicKey keyWithCorruptMac = result.moveValue();
 
     bytevec keysToSignMac;
     DeviceInfo deviceInfo;
     ProtectedData protectedData;
     auto status = provisionable_->generateCertificateRequest(
-            testMode, {keyWithCorruptMac}, getProdEekChain(), challenge_, &deviceInfo,
-            &protectedData, &keysToSignMac);
+            testMode, {keyWithCorruptMac}, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
+            challenge_, &deviceInfo, &protectedData, &keysToSignMac);
     ASSERT_FALSE(status.isOk()) << status.getMessage();
     EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
 }
@@ -695,7 +712,7 @@
     bool testMode = false;
     generateKeys(testMode, 4 /* numKeys */);
 
-    auto prodEekChain = getProdEekChain();
+    auto prodEekChain = getProdEekChain(rpcHardwareInfo.supportedEekCurve);
     auto [parsedChain, _, parseErr] = cppbor::parse(prodEekChain);
     ASSERT_NE(parsedChain, nullptr) << parseErr;
     ASSERT_NE(parsedChain->asArray(), nullptr);
@@ -726,7 +743,7 @@
 
     // Build an EEK chain that omits the first self-signed cert.
     auto truncatedChain = cppbor::Array();
-    auto [chain, _, parseErr] = cppbor::parse(getProdEekChain());
+    auto [chain, _, parseErr] = cppbor::parse(getProdEekChain(rpcHardwareInfo.supportedEekCurve));
     ASSERT_TRUE(chain);
     auto eekChain = chain->asArray();
     ASSERT_NE(eekChain, nullptr);
@@ -754,6 +771,7 @@
     bytevec keysToSignMac;
     DeviceInfo deviceInfo;
     ProtectedData protectedData;
+    generateTestEekChain(3);
     auto status = provisionable_->generateCertificateRequest(
             true /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
@@ -772,6 +790,7 @@
     bytevec keysToSignMac;
     DeviceInfo deviceInfo;
     ProtectedData protectedData;
+    generateTestEekChain(3);
     auto status = provisionable_->generateCertificateRequest(
             false /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
index 36969bb..bf2ab02 100644
--- a/security/keymint/support/Android.bp
+++ b/security/keymint/support/Android.bp
@@ -60,11 +60,15 @@
     export_include_dirs: [
         "include",
     ],
+    defaults: [
+        "keymint_use_latest_hal_aidl_ndk_shared",
+    ],
     shared_libs: [
         "libbase",
         "libcppbor_external",
         "libcppcose_rkp",
         "libcrypto",
+        "libkeymaster_portable",
         "libjsoncpp",
     ],
 }
@@ -76,6 +80,9 @@
         "libgmock",
         "libgtest_main",
     ],
+    defaults: [
+        "keymint_use_latest_hal_aidl_ndk_shared",
+    ],
     shared_libs: [
         "libbase",
         "libcppbor_external",
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 406b7a9..f3b8608 100644
--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -52,6 +52,34 @@
         0x31, 0xbf, 0x6b, 0xe8, 0x1e, 0x35, 0xe2, 0xf0, 0x2d, 0xce, 0x6c, 0x2f, 0x4f, 0xf2,
         0xf5, 0x4f, 0xa5, 0xd4, 0x83, 0xad, 0x96, 0xa2, 0xf1, 0x87, 0x58, 0x04};
 
+// The Google ECDSA P256 root key for the Endpoint Encryption Key chain, encoded as COSE_Sign1
+inline constexpr uint8_t kCoseEncodedEcdsa256RootCert[] = {
+    0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x58, 0x4d, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21,
+    0x58, 0x20, 0xf7, 0x14, 0x8a, 0xdb, 0x97, 0xf4, 0xcc, 0x53, 0xef, 0xd2, 0x64, 0x11, 0xc4, 0xe3,
+    0x75, 0x1f, 0x66, 0x1f, 0xa4, 0x71, 0x0c, 0x6c, 0xcf, 0xfa, 0x09, 0x46, 0x80, 0x74, 0x87, 0x54,
+    0xf2, 0xad, 0x22, 0x58, 0x20, 0x5e, 0x7f, 0x5b, 0xf6, 0xec, 0xe4, 0xf6, 0x19, 0xcc, 0xff, 0x13,
+    0x37, 0xfd, 0x0f, 0xa1, 0xc8, 0x93, 0xdb, 0x18, 0x06, 0x76, 0xc4, 0x5d, 0xe6, 0xd7, 0x6a, 0x77,
+    0x86, 0xc3, 0x2d, 0xaf, 0x8f, 0x58, 0x40, 0x2f, 0x97, 0x8e, 0x42, 0xfb, 0xbe, 0x07, 0x2d, 0x95,
+    0x47, 0x85, 0x47, 0x93, 0x40, 0xb0, 0x1f, 0xd4, 0x9b, 0x47, 0xa4, 0xc4, 0x44, 0xa9, 0xf2, 0xa1,
+    0x07, 0x87, 0x10, 0xc7, 0x9f, 0xcb, 0x11, 0xf4, 0xbf, 0x9f, 0xe8, 0x3b, 0xe0, 0xe7, 0x34, 0x4c,
+    0x15, 0xfc, 0x7b, 0xc3, 0x7e, 0x33, 0x05, 0xf4, 0xd1, 0x34, 0x3c, 0xed, 0x02, 0x04, 0x60, 0x7a,
+    0x15, 0xe0, 0x79, 0xd3, 0x8a, 0xff, 0x24};
+
+// The Google ECDSA P256 Endpoint Encryption Key certificate, encoded as COSE_Sign1
+inline constexpr uint8_t kCoseEncodedEcdsa256GeekCert[] = {
+    0x84, 0x43, 0xa1, 0x01, 0x26, 0xa0, 0x58, 0x71, 0xa6, 0x01, 0x02, 0x02, 0x58, 0x20, 0x35, 0x73,
+    0xb7, 0x3f, 0xa0, 0x8a, 0x80, 0x89, 0xb1, 0x26, 0x67, 0xe9, 0xcb, 0x7c, 0x75, 0xa1, 0xaf, 0x02,
+    0x61, 0xfc, 0x6e, 0x65, 0x03, 0x91, 0x3b, 0xd3, 0x4b, 0x7d, 0x14, 0x94, 0x3e, 0x46, 0x03, 0x38,
+    0x18, 0x20, 0x01, 0x21, 0x58, 0x20, 0xe0, 0x41, 0xcf, 0x2f, 0x0f, 0x34, 0x0f, 0x1c, 0x33, 0x2c,
+    0x41, 0xb0, 0xcf, 0xd7, 0x0c, 0x30, 0x55, 0x35, 0xd2, 0x1e, 0x6a, 0x47, 0x13, 0x4b, 0x2e, 0xd1,
+    0x48, 0x96, 0x7e, 0x24, 0x9c, 0x68, 0x22, 0x58, 0x20, 0x1f, 0xce, 0x45, 0xc5, 0xfb, 0x61, 0xba,
+    0x81, 0x21, 0xf9, 0xe5, 0x05, 0x9b, 0x9b, 0x39, 0x0e, 0x76, 0x86, 0x86, 0x47, 0xb8, 0x1e, 0x2f,
+    0x45, 0xf1, 0xce, 0xaf, 0xda, 0x3f, 0x80, 0x68, 0xdb, 0x58, 0x40, 0x8c, 0xb3, 0xba, 0x7e, 0x20,
+    0x3e, 0x32, 0xb0, 0x68, 0xdf, 0x60, 0xd1, 0x1d, 0x7d, 0xf0, 0xac, 0x38, 0x8e, 0x51, 0xbc, 0xff,
+    0x6c, 0xe1, 0x67, 0x3b, 0x4a, 0x79, 0xbc, 0x56, 0x78, 0xb3, 0x99, 0xd8, 0x7c, 0x8a, 0x07, 0xd8,
+    0xda, 0xb5, 0xb5, 0x7f, 0x71, 0xf4, 0xd8, 0x6b, 0xdf, 0x33, 0x27, 0x34, 0x7b, 0x65, 0xd1, 0x2a,
+    0xeb, 0x86, 0x99, 0x98, 0xab, 0x3a, 0xb4, 0x80, 0xaa, 0xbd, 0x50};
+
 /**
  * Generates random bytes.
  */
@@ -64,15 +92,15 @@
 };
 
 /**
- * Generates an X25518 EEK with the specified eekId and an Ed25519 chain of the
- * specified length. All keys are generated randomly.
+ * Based on the supportedEekCurve, Generates an X25519/ECDH with the specified eekId
+ * and an Ed25519/ECDSA chain of the specified length. All keys are generated randomly.
  */
-ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId);
+ErrMsgOr<EekChain> generateEekChain(int32_t supportedEekCurve, size_t length, const bytevec& eekId);
 
 /**
  * Returns the CBOR-encoded, production Google Endpoint Encryption Key chain.
  */
-bytevec getProdEekChain();
+bytevec getProdEekChain(int32_t supportedEekCurve);
 
 struct BccEntryData {
     bytevec pubKey;
@@ -96,17 +124,19 @@
 };
 
 /**
- * Take a given certificate request and output a JSON blob containing both the
- * build fingerprint and certificate request. This data may be serialized, then
- * later uploaded to the remote provisioning service. The input csr is not
- * validated, only encoded.
+ * Take a given instance name and certificate request, then output a JSON blob
+ * containing the name, build fingerprint and certificate request. This data may
+ * be serialized, then later uploaded to the remote provisioning service. The
+ * input csr is not validated, only encoded.
  *
  * Output format:
  *   {
  *     "build_fingerprint": <string>
  *     "csr": <base64 CBOR CSR>
+ *     "name": <string>
  *   }
  */
-JsonOutput jsonEncodeCsrWithBuild(const cppbor::Array& csr);
+JsonOutput jsonEncodeCsrWithBuild(const std::string instance_name,
+                                  const cppbor::Array& csr);
 
 }  // 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 35cb891..0dbea5b 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -17,10 +17,16 @@
 #include <iterator>
 #include <tuple>
 
+#include <aidl/android/hardware/security/keymint/RpcHardwareInfo.h>
 #include <android-base/properties.h>
 #include <cppbor.h>
 #include <json/json.h>
+#include <keymaster/km_openssl/ec_key.h>
+#include <keymaster/km_openssl/ecdsa_operation.h>
+#include <keymaster/km_openssl/openssl_err.h>
+#include <keymaster/km_openssl/openssl_utils.h>
 #include <openssl/base64.h>
+#include <openssl/evp.h>
 #include <openssl/rand.h>
 #include <remote_prov/remote_prov_utils.h>
 
@@ -30,6 +36,166 @@
 constexpr uint32_t kBccPayloadSubject = 2;
 constexpr int32_t kBccPayloadSubjPubKey = -4670552;
 constexpr int32_t kBccPayloadKeyUsage = -4670553;
+constexpr int kP256AffinePointSize = 32;
+
+using EC_KEY_Ptr = bssl::UniquePtr<EC_KEY>;
+using EVP_PKEY_Ptr = bssl::UniquePtr<EVP_PKEY>;
+using EVP_PKEY_CTX_Ptr = bssl::UniquePtr<EVP_PKEY_CTX>;
+
+ErrMsgOr<bytevec> ecKeyGetPrivateKey(const EC_KEY* ecKey) {
+    // Extract private key.
+    const BIGNUM* bignum = EC_KEY_get0_private_key(ecKey);
+    if (bignum == nullptr) {
+        return "Error getting bignum from private key";
+    }
+    // Pad with zeros in case the length is lesser than 32.
+    bytevec privKey(32, 0);
+    BN_bn2binpad(bignum, privKey.data(), privKey.size());
+    return privKey;
+}
+
+ErrMsgOr<bytevec> ecKeyGetPublicKey(const EC_KEY* ecKey) {
+    // Extract public key.
+    auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+    if (group.get() == nullptr) {
+        return "Error creating EC group by curve name";
+    }
+    const EC_POINT* point = EC_KEY_get0_public_key(ecKey);
+    if (point == nullptr) return "Error getting ecpoint from public key";
+
+    int size =
+        EC_POINT_point2oct(group.get(), point, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr);
+    if (size == 0) {
+        return "Error generating public key encoding";
+    }
+
+    bytevec publicKey;
+    publicKey.resize(size);
+    EC_POINT_point2oct(group.get(), point, POINT_CONVERSION_UNCOMPRESSED, publicKey.data(),
+                       publicKey.size(), nullptr);
+    return publicKey;
+}
+
+ErrMsgOr<std::tuple<bytevec, bytevec>> getAffineCoordinates(const bytevec& pubKey) {
+    auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+    if (group.get() == nullptr) {
+        return "Error creating EC group by curve name";
+    }
+    auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
+    if (EC_POINT_oct2point(group.get(), point.get(), pubKey.data(), pubKey.size(), nullptr) != 1) {
+        return "Error decoding publicKey";
+    }
+    BIGNUM_Ptr x(BN_new());
+    BIGNUM_Ptr y(BN_new());
+    BN_CTX_Ptr ctx(BN_CTX_new());
+    if (!ctx.get()) return "Failed to create BN_CTX instance";
+
+    if (!EC_POINT_get_affine_coordinates_GFp(group.get(), point.get(), x.get(), y.get(),
+                                             ctx.get())) {
+        return "Failed to get affine coordinates from ECPoint";
+    }
+    bytevec pubX(kP256AffinePointSize);
+    bytevec pubY(kP256AffinePointSize);
+    if (BN_bn2binpad(x.get(), pubX.data(), kP256AffinePointSize) != kP256AffinePointSize) {
+        return "Error in converting absolute value of x coordinate to big-endian";
+    }
+    if (BN_bn2binpad(y.get(), pubY.data(), kP256AffinePointSize) != kP256AffinePointSize) {
+        return "Error in converting absolute value of y coordinate to big-endian";
+    }
+    return std::make_tuple(std::move(pubX), std::move(pubY));
+}
+
+ErrMsgOr<std::tuple<bytevec, bytevec>> generateEc256KeyPair() {
+    auto ec_key = EC_KEY_Ptr(EC_KEY_new());
+    if (ec_key.get() == nullptr) {
+        return "Failed to allocate ec key";
+    }
+
+    auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+    if (group.get() == nullptr) {
+        return "Error creating EC group by curve name";
+    }
+
+    if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 ||
+        EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) {
+        return "Error generating key";
+    }
+
+    auto privKey = ecKeyGetPrivateKey(ec_key.get());
+    if (!privKey) return privKey.moveMessage();
+
+    auto pubKey = ecKeyGetPublicKey(ec_key.get());
+    if (!pubKey) return pubKey.moveMessage();
+
+    return std::make_tuple(pubKey.moveValue(), privKey.moveValue());
+}
+
+ErrMsgOr<std::tuple<bytevec, bytevec>> generateX25519KeyPair() {
+    /* Generate X25519 key pair */
+    bytevec pubKey(X25519_PUBLIC_VALUE_LEN);
+    bytevec privKey(X25519_PRIVATE_KEY_LEN);
+    X25519_keypair(pubKey.data(), privKey.data());
+    return std::make_tuple(std::move(pubKey), std::move(privKey));
+}
+
+ErrMsgOr<std::tuple<bytevec, bytevec>> generateED25519KeyPair() {
+    /* Generate ED25519 key pair */
+    bytevec pubKey(ED25519_PUBLIC_KEY_LEN);
+    bytevec privKey(ED25519_PRIVATE_KEY_LEN);
+    ED25519_keypair(pubKey.data(), privKey.data());
+    return std::make_tuple(std::move(pubKey), std::move(privKey));
+}
+
+ErrMsgOr<std::tuple<bytevec, bytevec>> generateKeyPair(int32_t supportedEekCurve, bool isEek) {
+    switch (supportedEekCurve) {
+    case RpcHardwareInfo::CURVE_25519:
+        if (isEek) {
+            return generateX25519KeyPair();
+        }
+        return generateED25519KeyPair();
+    case RpcHardwareInfo::CURVE_P256:
+        return generateEc256KeyPair();
+    default:
+        return "Unknown EEK Curve.";
+    }
+}
+
+ErrMsgOr<bytevec> constructCoseKey(int32_t supportedEekCurve, const bytevec& eekId,
+                                   const bytevec& pubKey) {
+    CoseKeyType keyType;
+    CoseKeyAlgorithm algorithm;
+    CoseKeyCurve curve;
+    bytevec pubX;
+    bytevec pubY;
+    switch (supportedEekCurve) {
+    case RpcHardwareInfo::CURVE_25519:
+        keyType = OCTET_KEY_PAIR;
+        algorithm = (eekId.empty()) ? EDDSA : ECDH_ES_HKDF_256;
+        curve = (eekId.empty()) ? ED25519 : cppcose::X25519;
+        pubX = pubKey;
+        break;
+    case RpcHardwareInfo::CURVE_P256: {
+        keyType = EC2;
+        algorithm = (eekId.empty()) ? ES256 : ECDH_ES_HKDF_256;
+        curve = P256;
+        auto affineCoordinates = getAffineCoordinates(pubKey);
+        if (!affineCoordinates) return affineCoordinates.moveMessage();
+        std::tie(pubX, pubY) = affineCoordinates.moveValue();
+    } break;
+    default:
+        return "Unknown EEK Curve.";
+    }
+    cppbor::Map coseKey = cppbor::Map()
+                              .add(CoseKey::KEY_TYPE, keyType)
+                              .add(CoseKey::ALGORITHM, algorithm)
+                              .add(CoseKey::CURVE, curve)
+                              .add(CoseKey::PUBKEY_X, pubX);
+
+    if (!pubY.empty()) coseKey.add(CoseKey::PUBKEY_Y, pubY);
+    if (!eekId.empty()) coseKey.add(CoseKey::KEY_ID, eekId);
+
+    return coseKey.canonicalize().encode();
+}
 
 bytevec kTestMacKey(32 /* count */, 0 /* byte value */);
 
@@ -39,7 +205,17 @@
     return retval;
 }
 
-ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId) {
+ErrMsgOr<cppbor::Array> constructCoseSign1(int32_t supportedEekCurve, const bytevec& key,
+                                           const bytevec& payload, const bytevec& aad) {
+    if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) {
+        return constructECDSACoseSign1(key, {} /* protectedParams */, payload, aad);
+    } else {
+        return cppcose::constructCoseSign1(key, payload, aad);
+    }
+}
+
+ErrMsgOr<EekChain> generateEekChain(int32_t supportedEekCurve, size_t length,
+                                    const bytevec& eekId) {
     if (length < 2) {
         return "EEK chain must contain at least 2 certs.";
     }
@@ -48,59 +224,62 @@
 
     bytevec prev_priv_key;
     for (size_t i = 0; i < length - 1; ++i) {
-        bytevec pub_key(ED25519_PUBLIC_KEY_LEN);
-        bytevec priv_key(ED25519_PRIVATE_KEY_LEN);
-
-        ED25519_keypair(pub_key.data(), priv_key.data());
+        auto keyPair = generateKeyPair(supportedEekCurve, false);
+        if (!keyPair) return keyPair.moveMessage();
+        auto [pub_key, priv_key] = keyPair.moveValue();
 
         // The first signing key is self-signed.
         if (prev_priv_key.empty()) prev_priv_key = priv_key;
 
-        auto coseSign1 = constructCoseSign1(prev_priv_key,
-                                            cppbor::Map() /* payload CoseKey */
-                                                    .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
-                                                    .add(CoseKey::ALGORITHM, EDDSA)
-                                                    .add(CoseKey::CURVE, ED25519)
-                                                    .add(CoseKey::PUBKEY_X, pub_key)
-                                                    .canonicalize()
-                                                    .encode(),
-                                            {} /* AAD */);
+        auto coseKey = constructCoseKey(supportedEekCurve, {}, pub_key);
+        if (!coseKey) return coseKey.moveMessage();
+
+        auto coseSign1 =
+            constructCoseSign1(supportedEekCurve, prev_priv_key, coseKey.moveValue(), {} /* AAD */);
         if (!coseSign1) return coseSign1.moveMessage();
         eekChain.add(coseSign1.moveValue());
 
         prev_priv_key = priv_key;
     }
+    auto keyPair = generateKeyPair(supportedEekCurve, true);
+    if (!keyPair) return keyPair.moveMessage();
+    auto [pub_key, priv_key] = keyPair.moveValue();
 
-    bytevec pub_key(X25519_PUBLIC_VALUE_LEN);
-    bytevec priv_key(X25519_PRIVATE_KEY_LEN);
-    X25519_keypair(pub_key.data(), priv_key.data());
+    auto coseKey = constructCoseKey(supportedEekCurve, eekId, pub_key);
+    if (!coseKey) return coseKey.moveMessage();
 
-    auto coseSign1 = constructCoseSign1(prev_priv_key,
-                                        cppbor::Map() /* payload CoseKey */
-                                                .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
-                                                .add(CoseKey::KEY_ID, eekId)
-                                                .add(CoseKey::ALGORITHM, ECDH_ES_HKDF_256)
-                                                .add(CoseKey::CURVE, cppcose::X25519)
-                                                .add(CoseKey::PUBKEY_X, pub_key)
-                                                .canonicalize()
-                                                .encode(),
-                                        {} /* AAD */);
+    auto coseSign1 =
+        constructCoseSign1(supportedEekCurve, prev_priv_key, coseKey.moveValue(), {} /* AAD */);
     if (!coseSign1) return coseSign1.moveMessage();
     eekChain.add(coseSign1.moveValue());
 
+    if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) {
+        // convert ec public key to x and y co-ordinates.
+        auto affineCoordinates = getAffineCoordinates(pub_key);
+        if (!affineCoordinates) return affineCoordinates.moveMessage();
+        auto [pubX, pubY] = affineCoordinates.moveValue();
+        pub_key.clear();
+        pub_key.insert(pub_key.begin(), pubX.begin(), pubX.end());
+        pub_key.insert(pub_key.end(), pubY.begin(), pubY.end());
+    }
+
     return EekChain{eekChain.encode(), pub_key, priv_key};
 }
 
-bytevec getProdEekChain() {
-    bytevec prodEek;
-    prodEek.reserve(1 + sizeof(kCoseEncodedRootCert) + sizeof(kCoseEncodedGeekCert));
-
-    // In CBOR encoding, 0x82 indicates an array of two items
-    prodEek.push_back(0x82);
-    prodEek.insert(prodEek.end(), std::begin(kCoseEncodedRootCert), std::end(kCoseEncodedRootCert));
-    prodEek.insert(prodEek.end(), std::begin(kCoseEncodedGeekCert), std::end(kCoseEncodedGeekCert));
-
-    return prodEek;
+bytevec getProdEekChain(int32_t supportedEekCurve) {
+    cppbor::Array chain;
+    if (supportedEekCurve == RpcHardwareInfo::CURVE_P256) {
+        chain.add(cppbor::EncodedItem(bytevec(std::begin(kCoseEncodedEcdsa256RootCert),
+                                              std::end(kCoseEncodedEcdsa256RootCert))));
+        chain.add(cppbor::EncodedItem(bytevec(std::begin(kCoseEncodedEcdsa256GeekCert),
+                                              std::end(kCoseEncodedEcdsa256GeekCert))));
+    } else {
+        chain.add(cppbor::EncodedItem(
+            bytevec(std::begin(kCoseEncodedRootCert), std::end(kCoseEncodedRootCert))));
+        chain.add(cppbor::EncodedItem(
+            bytevec(std::begin(kCoseEncodedGeekCert), std::end(kCoseEncodedGeekCert))));
+    }
+    return chain.encode();
 }
 
 ErrMsgOr<bytevec> validatePayloadAndFetchPubKey(const cppbor::Map* payload) {
@@ -139,7 +318,8 @@
     }
 
     auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
-    if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != EDDSA) {
+    if (!algorithm || !algorithm->asInt() ||
+        (algorithm->asInt()->value() != EDDSA && algorithm->asInt()->value() != ES256)) {
         return "Unsupported signature algorithm";
     }
 
@@ -152,15 +332,36 @@
     }
 
     bool selfSigned = signingCoseKey.empty();
-    auto key = CoseKey::parseEd25519(selfSigned ? *serializedKey : signingCoseKey);
-    if (!key) return "Bad signing key: " + key.moveMessage();
-
     bytevec signatureInput =
-            cppbor::Array().add("Signature1").add(*protectedParams).add(aad).add(*payload).encode();
+        cppbor::Array().add("Signature1").add(*protectedParams).add(aad).add(*payload).encode();
 
-    if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
-                        key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
-        return "Signature verification failed";
+    if (algorithm->asInt()->value() == EDDSA) {
+        auto key = CoseKey::parseEd25519(selfSigned ? *serializedKey : signingCoseKey);
+
+        if (!key) return "Bad signing key: " + key.moveMessage();
+
+        if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
+                            key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
+            return "Signature verification failed";
+        }
+    } else {  // P256
+        auto key = CoseKey::parseP256(selfSigned ? *serializedKey : signingCoseKey);
+        if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty() ||
+            key->getBstrValue(CoseKey::PUBKEY_Y)->empty()) {
+            return "Bad signing key: " + key.moveMessage();
+        }
+        auto publicKey = key->getEcPublicKey();
+        if (!publicKey) return publicKey.moveMessage();
+
+        auto ecdsaDerSignature = ecdsaCoseSignatureToDer(signature->value());
+        if (!ecdsaDerSignature) return ecdsaDerSignature.moveMessage();
+
+        // convert public key to uncompressed form.
+        publicKey->insert(publicKey->begin(), 0x04);
+
+        if (!verifyEcdsaDigest(publicKey.moveValue(), sha256(signatureInput), *ecdsaDerSignature)) {
+            return "Signature verification failed";
+        }
     }
 
     return serializedKey.moveValue();
@@ -207,7 +408,7 @@
     return result;
 }
 
-JsonOutput jsonEncodeCsrWithBuild(const cppbor::Array& csr) {
+JsonOutput jsonEncodeCsrWithBuild(const std::string instance_name, const cppbor::Array& csr) {
     const std::string kFingerprintProp = "ro.build.fingerprint";
 
     if (!::android::base::WaitForPropertyCreation(kFingerprintProp)) {
@@ -231,6 +432,7 @@
     }
 
     Json::Value json(Json::objectValue);
+    json["name"] = instance_name;
     json["build_fingerprint"] = ::android::base::GetProperty(kFingerprintProp, /*default=*/"");
     json["csr"] = base64.data();  // Boring writes a NUL-terminated c-string
 
diff --git a/security/keymint/support/remote_prov_utils_test.cpp b/security/keymint/support/remote_prov_utils_test.cpp
index 8697c51..0250cd6 100644
--- a/security/keymint/support/remote_prov_utils_test.cpp
+++ b/security/keymint/support/remote_prov_utils_test.cpp
@@ -14,8 +14,12 @@
  * limitations under the License.
  */
 
+#include "cppbor.h"
+#include "keymaster/cppcose/cppcose.h"
+#include <aidl/android/hardware/security/keymint/RpcHardwareInfo.h>
 #include <android-base/properties.h>
 #include <cppbor_parse.h>
+#include <cstdint>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <keymaster/android_keymaster_utils.h>
@@ -23,25 +27,120 @@
 #include <keymaster/remote_provisioning_utils.h>
 #include <openssl/curve25519.h>
 #include <remote_prov/remote_prov_utils.h>
-#include <cstdint>
-#include "cppbor.h"
-#include "keymaster/cppcose/cppcose.h"
 
 namespace aidl::android::hardware::security::keymint::remote_prov {
 namespace {
 
 using ::keymaster::KeymasterBlob;
-using ::keymaster::validateAndExtractEekPubAndId;
+using ::keymaster::kStatusFailed;
+using ::keymaster::kStatusInvalidEek;
+using ::keymaster::StatusOr;
 using ::testing::ElementsAreArray;
+using byte_view = std::basic_string_view<uint8_t>;
+
+struct KeyInfoEcdsa {
+    CoseKeyCurve curve;
+    byte_view pubKeyX;
+    byte_view pubKeyY;
+
+    bool operator==(const KeyInfoEcdsa& other) const {
+        return curve == other.curve && pubKeyX == other.pubKeyX && pubKeyY == other.pubKeyY;
+    }
+};
+
+// The production root signing key for Google ECDSA P256 Endpoint Encryption Key cert chains.
+inline constexpr uint8_t kEcdsa256GeekRootX[] = {
+    0xf7, 0x14, 0x8a, 0xdb, 0x97, 0xf4, 0xcc, 0x53, 0xef, 0xd2, 0x64, 0x11, 0xc4, 0xe3, 0x75, 0x1f,
+    0x66, 0x1f, 0xa4, 0x71, 0x0c, 0x6c, 0xcf, 0xfa, 0x09, 0x46, 0x80, 0x74, 0x87, 0x54, 0xf2, 0xad};
+
+inline constexpr uint8_t kEcdsa256GeekRootY[] = {
+    0x5e, 0x7f, 0x5b, 0xf6, 0xec, 0xe4, 0xf6, 0x19, 0xcc, 0xff, 0x13, 0x37, 0xfd, 0x0f, 0xa1, 0xc8,
+    0x93, 0xdb, 0x18, 0x06, 0x76, 0xc4, 0x5d, 0xe6, 0xd7, 0x6a, 0x77, 0x86, 0xc3, 0x2d, 0xaf, 0x8f};
+
+// Hard-coded set of acceptable public COSE_Keys that can act as roots of EEK chains.
+inline constexpr KeyInfoEcdsa kAuthorizedEcdsa256EekRoots[] = {
+    {CoseKeyCurve::P256, byte_view(kEcdsa256GeekRootX, sizeof(kEcdsa256GeekRootX)),
+     byte_view(kEcdsa256GeekRootY, sizeof(kEcdsa256GeekRootY))},
+};
+
+static ErrMsgOr<CoseKey> parseEcdh256(const bytevec& coseKey) {
+    auto key = CoseKey::parse(coseKey, EC2, ECDH_ES_HKDF_256, P256);
+    if (!key) return key;
+
+    auto& pubkey_x = key->getMap().get(cppcose::CoseKey::PUBKEY_X);
+    auto& pubkey_y = key->getMap().get(cppcose::CoseKey::PUBKEY_Y);
+    if (!pubkey_x || !pubkey_y || !pubkey_x->asBstr() || !pubkey_y->asBstr() ||
+        pubkey_x->asBstr()->value().size() != 32 || pubkey_y->asBstr()->value().size() != 32) {
+        return "Invalid P256 public key";
+    }
+
+    return key;
+}
+
+StatusOr<std::tuple<std::vector<uint8_t> /* EEK pubX */, std::vector<uint8_t> /* EEK pubY */,
+                    std::vector<uint8_t> /* EEK ID */>>
+validateAndExtractEcdsa256EekPubAndId(bool testMode,
+                                      const KeymasterBlob& endpointEncryptionCertChain) {
+    auto [item, newPos, errMsg] =
+        cppbor::parse(endpointEncryptionCertChain.begin(), endpointEncryptionCertChain.end());
+    if (!item || !item->asArray()) {
+        return kStatusFailed;
+    }
+    const cppbor::Array* certArr = item->asArray();
+    std::vector<uint8_t> lastPubKey;
+    for (size_t i = 0; i < certArr->size(); ++i) {
+        auto cosePubKey =
+            verifyAndParseCoseSign1(certArr->get(i)->asArray(), lastPubKey, {} /* AAD */);
+        if (!cosePubKey) {
+            return kStatusInvalidEek;
+        }
+        lastPubKey = *std::move(cosePubKey);
+
+        // In prod mode the first pubkey should match a well-known Google public key.
+        if (!testMode && i == 0) {
+            auto parsedPubKey = CoseKey::parse(lastPubKey);
+            if (!parsedPubKey) {
+                return kStatusFailed;
+            }
+            auto curve = parsedPubKey->getIntValue(CoseKey::CURVE);
+            if (!curve) {
+                return kStatusInvalidEek;
+            }
+            auto rawPubX = parsedPubKey->getBstrValue(CoseKey::PUBKEY_X);
+            if (!rawPubX) {
+                return kStatusInvalidEek;
+            }
+            auto rawPubY = parsedPubKey->getBstrValue(CoseKey::PUBKEY_Y);
+            if (!rawPubY) {
+                return kStatusInvalidEek;
+            }
+            KeyInfoEcdsa matcher = {static_cast<CoseKeyCurve>(*curve),
+                                    byte_view(rawPubX->data(), rawPubX->size()),
+                                    byte_view(rawPubY->data(), rawPubY->size())};
+            if (std::find(std::begin(kAuthorizedEcdsa256EekRoots),
+                          std::end(kAuthorizedEcdsa256EekRoots),
+                          matcher) == std::end(kAuthorizedEcdsa256EekRoots)) {
+                return kStatusInvalidEek;
+            }
+        }
+    }
+    auto eek = parseEcdh256(lastPubKey);
+    if (!eek) {
+        return kStatusInvalidEek;
+    }
+    return std::make_tuple(eek->getBstrValue(CoseKey::PUBKEY_X).value(),
+                           eek->getBstrValue(CoseKey::PUBKEY_Y).value(),
+                           eek->getBstrValue(CoseKey::KEY_ID).value());
+}
 
 TEST(RemoteProvUtilsTest, GenerateEekChainInvalidLength) {
-    ASSERT_FALSE(generateEekChain(1, /*eekId=*/{}));
+    ASSERT_FALSE(generateEekChain(RpcHardwareInfo::CURVE_25519, 1, /*eekId=*/{}));
 }
 
 TEST(RemoteProvUtilsTest, GenerateEekChain) {
     bytevec kTestEekId = {'t', 'e', 's', 't', 'I', 'd', 0};
     for (size_t length : {2, 3, 31}) {
-        auto get_eek_result = generateEekChain(length, kTestEekId);
+        auto get_eek_result = generateEekChain(RpcHardwareInfo::CURVE_25519, length, kTestEekId);
         ASSERT_TRUE(get_eek_result) << get_eek_result.message();
 
         auto& [chain, pubkey, privkey] = *get_eek_result;
@@ -57,7 +156,7 @@
 }
 
 TEST(RemoteProvUtilsTest, GetProdEekChain) {
-    auto chain = getProdEekChain();
+    auto chain = getProdEekChain(RpcHardwareInfo::CURVE_25519);
 
     auto validation_result = validateAndExtractEekPubAndId(
             /*testMode=*/false, KeymasterBlob(chain.data(), chain.size()));
@@ -86,16 +185,68 @@
     cppbor::Array array;
     array.add(1);
 
-    auto [json, error] = jsonEncodeCsrWithBuild(array);
+    auto [json, error] = jsonEncodeCsrWithBuild(std::string("test"), array);
 
     ASSERT_TRUE(error.empty()) << error;
 
     std::string expected = R"({"build_fingerprint":")" +
                            ::android::base::GetProperty("ro.build.fingerprint", /*default=*/"") +
-                           R"(","csr":"gQE="})";
+                           R"(","csr":"gQE=","name":"test"})";
 
     ASSERT_EQ(json, expected);
 }
 
+TEST(RemoteProvUtilsTest, GenerateEcdsaEekChainInvalidLength) {
+    ASSERT_FALSE(generateEekChain(RpcHardwareInfo::CURVE_P256, 1, /*eekId=*/{}));
+}
+
+TEST(RemoteProvUtilsTest, GenerateEcdsaEekChain) {
+    bytevec kTestEekId = {'t', 'e', 's', 't', 'I', 'd', 0};
+    for (size_t length : {2, 3, 31}) {
+        auto get_eek_result = generateEekChain(RpcHardwareInfo::CURVE_P256, length, kTestEekId);
+        ASSERT_TRUE(get_eek_result) << get_eek_result.message();
+
+        auto& [chain, pubkey, privkey] = *get_eek_result;
+
+        auto validation_result = validateAndExtractEcdsa256EekPubAndId(
+            /*testMode=*/true, KeymasterBlob(chain.data(), chain.size()));
+        ASSERT_TRUE(validation_result.isOk());
+
+        auto& [eekPubX, eekPubY, eekId] = *validation_result;
+        bytevec eekPub;
+        eekPub.insert(eekPub.begin(), eekPubX.begin(), eekPubX.end());
+        eekPub.insert(eekPub.end(), eekPubY.begin(), eekPubY.end());
+        EXPECT_THAT(eekId, ElementsAreArray(kTestEekId));
+        EXPECT_THAT(eekPub, ElementsAreArray(pubkey));
+    }
+}
+
+TEST(RemoteProvUtilsTest, GetProdEcdsaEekChain) {
+    auto chain = getProdEekChain(RpcHardwareInfo::CURVE_P256);
+
+    auto validation_result = validateAndExtractEcdsa256EekPubAndId(
+        /*testMode=*/false, KeymasterBlob(chain.data(), chain.size()));
+    ASSERT_TRUE(validation_result.isOk()) << "Error: " << validation_result.moveError();
+
+    auto& [eekPubX, eekPubY, eekId] = *validation_result;
+
+    auto [geekCert, ignoredNewPos, error] =
+        cppbor::parse(kCoseEncodedEcdsa256GeekCert, sizeof(kCoseEncodedEcdsa256GeekCert));
+    ASSERT_NE(geekCert, nullptr) << "Error: " << error;
+    ASSERT_NE(geekCert->asArray(), nullptr);
+
+    auto& encodedGeekCoseKey = geekCert->asArray()->get(kCoseSign1Payload);
+    ASSERT_NE(encodedGeekCoseKey, nullptr);
+    ASSERT_NE(encodedGeekCoseKey->asBstr(), nullptr);
+
+    auto geek = CoseKey::parse(encodedGeekCoseKey->asBstr()->value());
+    ASSERT_TRUE(geek) << "Error: " << geek.message();
+
+    const std::vector<uint8_t> empty;
+    EXPECT_THAT(eekId, ElementsAreArray(geek->getBstrValue(CoseKey::KEY_ID).value_or(empty)));
+    EXPECT_THAT(eekPubX, ElementsAreArray(geek->getBstrValue(CoseKey::PUBKEY_X).value_or(empty)));
+    EXPECT_THAT(eekPubY, ElementsAreArray(geek->getBstrValue(CoseKey::PUBKEY_Y).value_or(empty)));
+}
+
 }  // namespace
 }  // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp
index 9a92fb3..274cfa7 100644
--- a/sensors/1.0/vts/functional/Android.bp
+++ b/sensors/1.0/vts/functional/Android.bp
@@ -27,6 +27,9 @@
     name: "VtsHalSensorsV1_0TargetTest",
     cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: [
+        "VtsHalSensorsV1_0TargetTest.cpp",
+    ],
     srcs: [
         "SensorsHidlEnvironmentV1_0.cpp",
         "VtsHalSensorsV1_0TargetTest.cpp",
diff --git a/sensors/2.0/vts/functional/Android.bp b/sensors/2.0/vts/functional/Android.bp
index cf7c9fa..c4ec866 100644
--- a/sensors/2.0/vts/functional/Android.bp
+++ b/sensors/2.0/vts/functional/Android.bp
@@ -27,6 +27,9 @@
     name: "VtsHalSensorsV2_0TargetTest",
     cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: [
+        "VtsHalSensorsV2_0TargetTest.cpp",
+    ],
     srcs: [
         "VtsHalSensorsV2_0TargetTest.cpp",
     ],
diff --git a/sensors/aidl/android/hardware/sensors/Event.aidl b/sensors/aidl/android/hardware/sensors/Event.aidl
index e8550f1..b95299c 100644
--- a/sensors/aidl/android/hardware/sensors/Event.aidl
+++ b/sensors/aidl/android/hardware/sensors/Event.aidl
@@ -204,6 +204,8 @@
              * velocity of the head (relative to itself), in radians per second.
              * The direction of this vector indicates the axis of rotation, and
              * the magnitude indicates the rate of rotation.
+             * If this head tracker sensor instance does not support detecting
+             * velocity, then these fields must be set to 0.
              */
             float vx;
             float vy;
diff --git a/sensors/aidl/default/multihal/ConvertUtils.cpp b/sensors/aidl/default/multihal/ConvertUtils.cpp
index 7751fd2..9b2d8fe 100644
--- a/sensors/aidl/default/multihal/ConvertUtils.cpp
+++ b/sensors/aidl/default/multihal/ConvertUtils.cpp
@@ -173,7 +173,7 @@
                 }
                 default:
                     ALOGE("Invalid sensor additioanl info tag: %d",
-                          additionalInfo.payload.getTag());
+                          static_cast<int32_t>(additionalInfo.payload.getTag()));
                     break;
             }
             break;
diff --git a/sensors/common/default/2.X/multihal/tests/Android.bp b/sensors/common/default/2.X/multihal/tests/Android.bp
index d8e7ce6..21d1d77 100644
--- a/sensors/common/default/2.X/multihal/tests/Android.bp
+++ b/sensors/common/default/2.X/multihal/tests/Android.bp
@@ -99,6 +99,9 @@
 
 cc_test {
     name: "android.hardware.sensors@2.X-halproxy-unit-tests",
+    tidy_timeout_srcs: [
+        "HalProxy_test.cpp",
+    ],
     srcs: [
         "HalProxy_test.cpp",
         "ScopedWakelock_test.cpp",
diff --git a/thermal/2.0/vts/functional/Android.bp b/thermal/2.0/vts/functional/Android.bp
index f26c1af..29dffcb 100644
--- a/thermal/2.0/vts/functional/Android.bp
+++ b/thermal/2.0/vts/functional/Android.bp
@@ -26,6 +26,7 @@
 cc_test {
     name: "VtsHalThermalV2_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: ["VtsHalThermalV2_0TargetTest.cpp"],
     srcs: ["VtsHalThermalV2_0TargetTest.cpp"],
     static_libs: [
         "android.hardware.thermal@1.0",
diff --git a/tv/Android.mk b/tv/Android.mk
new file mode 100644
index 0000000..d78614a
--- /dev/null
+++ b/tv/Android.mk
@@ -0,0 +1,2 @@
+$(eval $(call declare-1p-copy-files,hardware/interfaces/tv,tuner_vts_config_1_0.xml))
+$(eval $(call declare-1p-copy-files,hardware/interfaces/tv,tuner_vts_config_1_1.xml))
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/IFrontend.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/IFrontend.aidl
index 12f2692..9cbd3dd 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/IFrontend.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/IFrontend.aidl
@@ -142,7 +142,9 @@
      * Request Hardware information about the frontend.
      *
      * The client may use this to collect vendor specific hardware information, e.g. RF
-     * chip version, Demod chip version, detailed status of dvbs blind scan, etc.
+     * chip version, Demod chip version, detailed status of dvbs blind scan, etc. The
+     * client shouldn’t parse things or rely on any format or change their behavior
+     * based on results.
      *
      * @return the frontend hardware information.
      */
diff --git a/update-base-files.sh b/update-base-files.sh
index d01847d..bf7f6e4 100755
--- a/update-base-files.sh
+++ b/update-base-files.sh
@@ -45,8 +45,11 @@
          -o $ANDROID_BUILD_TOP/system/media/audio/include/system/audio_common-base.h \
          android.hardware.audio.common@7.0
 hidl-gen $options \
-         -o $ANDROID_BUILD_TOP/system/media/audio/include/system/audio-base.h \
+         -o $ANDROID_BUILD_TOP/system/media/audio/include/system/audio-base-v7.0.h \
          android.hardware.audio@7.0
 hidl-gen $options \
+         -o $ANDROID_BUILD_TOP/system/media/audio/include/system/audio-base-v7.1.h \
+         android.hardware.audio@7.1
+hidl-gen $options \
          -o $ANDROID_BUILD_TOP/system/media/audio/include/system/audio_effect-base.h \
          android.hardware.audio.effect@7.0
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGids.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGids.aidl
index b0d88e0..5515c67 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGids.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGids.aidl
@@ -34,5 +34,5 @@
 package android.hardware.uwb.fira_android;
 @Backing(type="byte") @VintfStability
 enum UwbVendorGids {
-  ANDROID = 14,
+  ANDROID = 12,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorStatusCodes.aidl
similarity index 80%
copy from drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl
copy to uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorStatusCodes.aidl
index d2b48d2..2f534df 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorStatusCodes.aidl
@@ -1,11 +1,11 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
+ * You may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *        http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -31,9 +31,9 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.drm;
-@VintfStability
-parcelable DecryptResult {
-  int bytesWritten;
-  String detailedError;
+package android.hardware.uwb.fira_android;
+@Backing(type="byte") @VintfStability
+enum UwbVendorStatusCodes {
+  STATUS_ERROR_CCC_SE_BUSY = 80,
+  STATUS_ERROR_CCC_LIFECYCLE = 81,
 }
diff --git a/uwb/aidl/android/hardware/uwb/IUwbChip.aidl b/uwb/aidl/android/hardware/uwb/IUwbChip.aidl
index 00cb8e0..6ee5799 100644
--- a/uwb/aidl/android/hardware/uwb/IUwbChip.aidl
+++ b/uwb/aidl/android/hardware/uwb/IUwbChip.aidl
@@ -71,8 +71,8 @@
      * The UCI message format is as per UCI  protocol and it is
      * defined in "FiRa Consortium - UCI Generic Specification_v1.0" specification at FiRa
      * consortium.
-     * WIP doc link: https://groups.firaconsortium.org/wg/Technical/document/folder/127.
-     * TODO(b/196004116): Link to the published specification.
+     *
+     * UCI 1.1 specification: https://groups.firaconsortium.org/wg/members/document/1949.
      *
      * This method may queue writes and return immediately, or it may block until data is written.
      * Implementation must guarantee that writes are executed in order.
diff --git a/uwb/aidl/android/hardware/uwb/IUwbClientCallback.aidl b/uwb/aidl/android/hardware/uwb/IUwbClientCallback.aidl
index 75853cd..f31aeba 100755
--- a/uwb/aidl/android/hardware/uwb/IUwbClientCallback.aidl
+++ b/uwb/aidl/android/hardware/uwb/IUwbClientCallback.aidl
@@ -28,8 +28,7 @@
      * can use to pass incoming data to the stack.  These include UCI
      * responses and notifications from the UWB subsystem.
      *
-     * WIP doc link: https://groups.firaconsortium.org/wg/Technical/document/folder/127.
-     * TODO(b/196004116): Link to the published specification.
+     * UCI 1.1 specification: https://groups.firaconsortium.org/wg/members/document/1949.
      *
      * @param data UCI packet sent.
      */
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index 97f8010..0140fdd 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -129,9 +129,9 @@
      * 1 byte tuple {initiator_tx (4 bits), responder_tx (4 bits)} array with list of supported
      * pulse shape combos
      * Values:
-     *  PULSE_SHAPE_SYMMETRICAL_ROOT_RAISED_COSINE = 1
-     *  PULSE_SHAPE_PRECURSOR_FREE = 2
-     *  PULSE_SHAPE_PRECURSOR_FREE_SPECIAL = 3
+     *  PULSE_SHAPE_SYMMETRICAL_ROOT_RAISED_COSINE = 0
+     *  PULSE_SHAPE_PRECURSOR_FREE = 1
+     *  PULSE_SHAPE_PRECURSOR_FREE_SPECIAL = 2
      */
     /**  */
     CCC_SUPPORTED_PULSE_SHAPE_COMBOS = 0xA6,
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
index c04bdcf..e389a2d 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
@@ -19,6 +19,7 @@
 /**
  * Android specific vendor command OIDs should be defined here.
  *
+ * For use with Android GID - 0xC.
  */
 @VintfStability
 @Backing(type="byte")
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGids.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGids.aidl
index c7bc6b0..dbe00cb 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGids.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGids.aidl
@@ -32,5 +32,5 @@
      */
 
     /** All Android specific commands/response/notification should use this GID */
-    ANDROID = 0xE,
+    ANDROID = 0xC,
 }
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
index 8547567..f43b249 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
@@ -60,10 +60,10 @@
      * Supported only if the UwbVendorCapabilityTlvTypes
      * .SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING set to 1.
      */
-    /** 2 byte data */
+    /** 1 byte data */
     NB_OF_RANGE_MEASUREMENTS = 0xE3,
-    /** 2 byte data */
+    /** 1 byte data */
     NB_OF_AZIMUTH_MEASUREMENTS = 0xE4,
-    /** 2 byte data */
+    /** 1 byte data */
     NB_OF_ELEVATION_MEASUREMENTS = 0xE5,
 }
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorStatusCodes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorStatusCodes.aidl
new file mode 100644
index 0000000..8505b8a
--- /dev/null
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorStatusCodes.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.uwb.fira_android;
+
+/**
+ * Android specific vendor status codes should be defined here.
+ *
+ */
+@VintfStability
+@Backing(type="byte")
+enum UwbVendorStatusCodes {
+    /**
+     * Use values from the vendor specific status code range: 0x50 – 0xFF defined in Table 32 of
+     * UCI specification.
+     */
+
+    /** CCC specific */
+    /** Secure element is busy */
+    STATUS_ERROR_CCC_SE_BUSY = 0x50,
+    /** CCC Lifecycle error */
+    STATUS_ERROR_CCC_LIFECYCLE = 0x51,
+}
diff --git a/vibrator/aidl/Android.bp b/vibrator/aidl/Android.bp
index 22219b0..d4d5857 100644
--- a/vibrator/aidl/Android.bp
+++ b/vibrator/aidl/Android.bp
@@ -10,6 +10,7 @@
 aidl_interface {
     name: "android.hardware.vibrator",
     vendor_available: true,
+    host_supported: true,
     srcs: [
         "android/hardware/vibrator/*.aidl",
     ],
diff --git a/vibrator/aidl/OWNERS b/vibrator/aidl/OWNERS
index ae10db6..3982c7b 100644
--- a/vibrator/aidl/OWNERS
+++ b/vibrator/aidl/OWNERS
@@ -1,4 +1,4 @@
 # Bug component: 345036
 include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
 chasewu@google.com
-leungv@google.com
+taikuo@google.com
diff --git a/vibrator/aidl/default/Android.bp b/vibrator/aidl/default/Android.bp
index 2e12dfb..acdbdcd 100644
--- a/vibrator/aidl/default/Android.bp
+++ b/vibrator/aidl/default/Android.bp
@@ -9,7 +9,8 @@
 
 cc_library_static {
     name: "libvibratorexampleimpl",
-    vendor: true,
+    vendor_available: true,
+    host_supported: true,
     shared_libs: [
         "libbase",
         "libbinder_ndk",
@@ -24,6 +25,11 @@
         ":__subpackages__",
         "//hardware/interfaces/tests/extension/vibrator:__subpackages__",
     ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
 }
 
 filegroup {
@@ -47,3 +53,40 @@
     ],
     srcs: ["main.cpp"],
 }
+
+cc_fuzz {
+    name: "android.hardware.vibrator-service.example_fuzzer",
+    host_supported: true,
+    static_libs: [
+        "android.hardware.vibrator-V2-ndk",
+        "libbase",
+        "libbinder_random_parcel",
+        "libcutils",
+        "liblog",
+        "libutils",
+        "libvibratorexampleimpl",
+    ],
+    target: {
+        android: {
+            shared_libs: [
+                "libbinder_ndk",
+                "libbinder",
+            ],
+        },
+        host: {
+            static_libs: [
+                "libbinder_ndk",
+                "libbinder",
+            ],
+        },
+        darwin: {
+            enabled: false,
+        },
+    },
+    srcs: ["fuzzer.cpp"],
+    fuzz_config: {
+        cc: [
+            "smoreland@google.com",
+        ],
+    },
+}
diff --git a/vibrator/aidl/default/fuzzer.cpp b/vibrator/aidl/default/fuzzer.cpp
new file mode 100644
index 0000000..7d52209
--- /dev/null
+++ b/vibrator/aidl/default/fuzzer.cpp
@@ -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.
+ */
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <vibrator-impl/Vibrator.h>
+#include <vibrator-impl/VibratorManager.h>
+
+using aidl::android::hardware::vibrator::Vibrator;
+using aidl::android::hardware::vibrator::VibratorManager;
+using android::fuzzService;
+using ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    auto managedVib = SharedRefBase::make<Vibrator>();
+    auto vibManager = SharedRefBase::make<VibratorManager>(std::move(managedVib));
+
+    fuzzService(vibManager->asBinder().get(), FuzzedDataProvider(data, size));
+
+    return 0;
+}
diff --git a/vibrator/aidl/vts/Android.bp b/vibrator/aidl/vts/Android.bp
index 3f328fa..1261870 100644
--- a/vibrator/aidl/vts/Android.bp
+++ b/vibrator/aidl/vts/Android.bp
@@ -13,6 +13,7 @@
         "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
     ],
+    tidy_timeout_srcs: ["VtsHalVibratorTargetTest.cpp"],
     srcs: ["VtsHalVibratorTargetTest.cpp"],
     shared_libs: [
         "libbinder",
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index 09cc21b..abb80a2 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -167,9 +167,9 @@
         EXPECT_TRUE(isUnknownOrUnsupported(status)) << status;
     }
 
-    float freqMaximumHz =
-        (bandwidthAmplitudeMap.size() * getFrequencyResolutionHz(vibrator, capabilities)) +
-        getFrequencyMinimumHz(vibrator, capabilities);
+    float freqMaximumHz = ((bandwidthAmplitudeMap.size() - 1) *
+                           getFrequencyResolutionHz(vibrator, capabilities)) +
+                          getFrequencyMinimumHz(vibrator, capabilities);
     return freqMaximumHz;
 }
 
diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp
index 6c0ebf7..ebfa164 100644
--- a/wifi/1.0/vts/functional/Android.bp
+++ b/wifi/1.0/vts/functional/Android.bp
@@ -48,6 +48,9 @@
 cc_test {
     name: "VtsHalWifiV1_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: [
+        "wifi_chip_hidl_test.cpp",
+    ],
     srcs: [
         "wifi_chip_hidl_test.cpp",
         "wifi_p2p_iface_hidl_test.cpp",
diff --git a/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp
index 72cde3c..8918997 100644
--- a/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp
+++ b/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp
@@ -66,7 +66,9 @@
         stopWifi(GetInstanceName());
 
         wifi_rtt_controller_ = getWifiRttController();
-        ASSERT_NE(nullptr, wifi_rtt_controller_.get());
+        if (wifi_rtt_controller_.get() == nullptr) {
+            GTEST_SKIP() << "Skipping this test since API is deprecated.";
+        }
 
         // Check RTT support before we run the test.
         std::pair<WifiStatus, RttCapabilities> status_and_caps;
@@ -79,7 +81,7 @@
 
     virtual void TearDown() override { stopWifi(GetInstanceName()); }
 
-    // A simple test implementation of WifiChipEventCallback.
+    // A simple test implementation of WifiRttControllerEventCallback.
     class WifiRttControllerEventCallback
         : public ::testing::VtsHalHidlTargetCallbackBase<
               WifiRttControllerHidlTest>,
@@ -122,6 +124,11 @@
 
         const auto& status_and_controller =
             HIDL_INVOKE(wifi_chip, createRttController_1_4, wifi_sta_iface);
+
+        if (status_and_controller.first.code == WifiStatusCode::ERROR_NOT_SUPPORTED) {
+            return nullptr;
+        }
+
         EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_controller.first.code);
         EXPECT_NE(nullptr, status_and_controller.second.get());
 
diff --git a/wifi/1.5/vts/functional/Android.bp b/wifi/1.5/vts/functional/Android.bp
index 764d14d..d906d06 100644
--- a/wifi/1.5/vts/functional/Android.bp
+++ b/wifi/1.5/vts/functional/Android.bp
@@ -83,6 +83,7 @@
         "android.hardware.wifi@1.3",
         "android.hardware.wifi@1.4",
         "android.hardware.wifi@1.5",
+        "android.hardware.wifi@1.6",
         "libwifi-system-iface",
     ],
     test_suites: [
diff --git a/wifi/1.5/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.5/vts/functional/wifi_nan_iface_hidl_test.cpp
index 803d39d..8474d78 100644
--- a/wifi/1.5/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.5/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -20,6 +20,7 @@
 #include <android/hardware/wifi/1.5/IWifi.h>
 #include <android/hardware/wifi/1.5/IWifiNanIface.h>
 #include <android/hardware/wifi/1.5/IWifiNanIfaceEventCallback.h>
+#include <android/hardware/wifi/1.6/IWifiNanIface.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
@@ -34,7 +35,6 @@
 using namespace ::android::hardware::wifi::V1_2;
 using namespace ::android::hardware::wifi::V1_4;
 using namespace ::android::hardware::wifi::V1_5;
-
 using ::android::sp;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
@@ -586,6 +586,11 @@
  * getCapabilitiesRequest: validate that returns capabilities.
  */
 TEST_P(WifiNanIfaceHidlTest, getCapabilitiesRequest_1_5) {
+    sp<::android::hardware::wifi::V1_6::IWifiNanIface> iface_converted =
+            ::android::hardware::wifi::V1_6::IWifiNanIface::castFrom(iwifiNanIface);
+    if (iface_converted != nullptr) {
+        return;
+    }
     uint16_t inputCmdId = 10;
     callbackType = INVALID;
     const auto& halStatus =
diff --git a/wifi/1.5/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.5/vts/functional/wifi_sta_iface_hidl_test.cpp
index 399307e..7a0eb1f 100644
--- a/wifi/1.5/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.5/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -94,6 +94,11 @@
     // Retrieve link layer stats.
     const auto& status_and_stats =
         HIDL_INVOKE(wifi_sta_iface_, getLinkLayerStats_1_5);
+
+    if (status_and_stats.first.code == WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        GTEST_SKIP() << "Skipping this test since API is deprecated.";
+    }
+
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_stats.first.code);
     EXPECT_GT(status_and_stats.second.timeStampInMs, 0u);
     // Try to create 2nd iface. If yes, it should fill in the duty cycle field.
diff --git a/wifi/1.6/default/tests/mock_wifi_legacy_hal.h b/wifi/1.6/default/tests/mock_wifi_legacy_hal.h
index b1f5327..85dbf0f 100644
--- a/wifi/1.6/default/tests/mock_wifi_legacy_hal.h
+++ b/wifi/1.6/default/tests/mock_wifi_legacy_hal.h
@@ -56,6 +56,10 @@
                  wifi_error(const std::string& ifname, wifi_interface_type iftype));
     MOCK_METHOD1(deleteVirtualInterface, wifi_error(const std::string& ifname));
     MOCK_METHOD0(waitForDriverReady, wifi_error());
+    MOCK_METHOD2(getSupportedIfaceName, wifi_error(uint32_t, std::string&));
+    MOCK_METHOD1(registerSubsystemRestartCallbackHandler,
+                 wifi_error(const on_subsystem_restart_callback&));
+    MOCK_METHOD1(getSupportedFeatureSet, std::pair<wifi_error, uint64_t>(const std::string&));
 };
 }  // namespace legacy_hal
 }  // namespace implementation
diff --git a/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp
index 48c0065..81117c5 100644
--- a/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp
+++ b/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp
@@ -278,6 +278,9 @@
                 .WillRepeatedly(testing::Return(true));
         EXPECT_CALL(*legacy_hal_, start())
                 .WillRepeatedly(testing::Return(legacy_hal::WIFI_SUCCESS));
+        // Vendor HAL does not override the name by default.
+        EXPECT_CALL(*legacy_hal_, getSupportedIfaceName(testing::_, testing::_))
+                .WillRepeatedly(testing::Return(legacy_hal::WIFI_ERROR_UNKNOWN));
     }
 
     void TearDown() override {
@@ -843,13 +846,15 @@
 }
 
 TEST_F(WifiChip_MultiIfaceTest, CreateApStartsWithIdx1) {
+    // WifiChip_MultiIfaceTest iface combo: STAx3 + APx1
+    // When the HAL support dual STAs, AP should start with idx 2.
     findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
     // First AP will be slotted to wlan1.
-    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan2");
     // First STA will be slotted to wlan0.
     ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
     // All further STA will be slotted to the remaining free indices.
-    ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan1");
     ASSERT_EQ(createIface(IfaceType::STA), "wlan3");
 }
 }  // namespace implementation
diff --git a/wifi/1.6/default/wifi_chip.cpp b/wifi/1.6/default/wifi_chip.cpp
index 0e2accf..6cc1235 100644
--- a/wifi/1.6/default/wifi_chip.cpp
+++ b/wifi/1.6/default/wifi_chip.cpp
@@ -791,8 +791,57 @@
 
 std::pair<WifiStatus, std::vector<V1_0::IWifiChip::ChipMode>>
 WifiChip::getAvailableModesInternal() {
-    // Deprecated support -- use getAvailableModes_1_6.
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+    // Deprecated support -- use getAvailableModes_1_6 for more granular concurrency combinations.
+    std::vector<V1_0::IWifiChip::ChipMode> modes_1_0 = {};
+    for (const auto& mode_1_6 : modes_) {
+        std::vector<V1_0::IWifiChip::ChipIfaceCombination> combos_1_0;
+        for (const auto& combo_1_6 : mode_1_6.availableCombinations) {
+            std::vector<V1_0::IWifiChip::ChipIfaceCombinationLimit> limits_1_0;
+            for (const auto& limit_1_6 : combo_1_6.limits) {
+                std::vector<IfaceType> types_1_0;
+                for (IfaceConcurrencyType type_1_6 : limit_1_6.types) {
+                    switch (type_1_6) {
+                        case IfaceConcurrencyType::STA:
+                            types_1_0.push_back(IfaceType::STA);
+                            break;
+                        case IfaceConcurrencyType::AP:
+                            types_1_0.push_back(IfaceType::AP);
+                            break;
+                        case IfaceConcurrencyType::AP_BRIDGED:
+                            // Ignore AP_BRIDGED
+                            break;
+                        case IfaceConcurrencyType::P2P:
+                            types_1_0.push_back(IfaceType::P2P);
+                            break;
+                        case IfaceConcurrencyType::NAN:
+                            types_1_0.push_back(IfaceType::NAN);
+                            break;
+                    }
+                }
+                if (types_1_0.empty()) {
+                    continue;
+                }
+                V1_0::IWifiChip::ChipIfaceCombinationLimit limit_1_0;
+                limit_1_0.types = hidl_vec(types_1_0);
+                limit_1_0.maxIfaces = limit_1_6.maxIfaces;
+                limits_1_0.push_back(limit_1_0);
+            }
+            if (limits_1_0.empty()) {
+                continue;
+            }
+            V1_0::IWifiChip::ChipIfaceCombination combo_1_0;
+            combo_1_0.limits = hidl_vec(limits_1_0);
+            combos_1_0.push_back(combo_1_0);
+        }
+        if (combos_1_0.empty()) {
+            continue;
+        }
+        V1_0::IWifiChip::ChipMode mode_1_0;
+        mode_1_0.id = mode_1_6.id;
+        mode_1_0.availableCombinations = hidl_vec(combos_1_0);
+        modes_1_0.push_back(mode_1_0);
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), modes_1_0};
 }
 
 WifiStatus WifiChip::configureChipInternal(
diff --git a/wifi/1.6/default/wifi_legacy_hal.h b/wifi/1.6/default/wifi_legacy_hal.h
index ab21e8e..6f42f70 100644
--- a/wifi/1.6/default/wifi_legacy_hal.h
+++ b/wifi/1.6/default/wifi_legacy_hal.h
@@ -496,7 +496,7 @@
             const std::string& iface_name);
     std::pair<wifi_error, std::vector<uint8_t>> requestFirmwareMemoryDump(
             const std::string& iface_name);
-    std::pair<wifi_error, uint64_t> getSupportedFeatureSet(const std::string& iface_name);
+    virtual std::pair<wifi_error, uint64_t> getSupportedFeatureSet(const std::string& iface_name);
     // APF functions.
     std::pair<wifi_error, PacketFilterCapabilities> getPacketFilterCapabilities(
             const std::string& iface_name);
@@ -564,7 +564,7 @@
     wifi_error registerRingBufferCallbackHandler(
             const std::string& iface_name, const on_ring_buffer_data_callback& on_data_callback);
     wifi_error deregisterRingBufferCallbackHandler(const std::string& iface_name);
-    wifi_error registerSubsystemRestartCallbackHandler(
+    virtual wifi_error registerSubsystemRestartCallbackHandler(
             const on_subsystem_restart_callback& on_restart_callback);
     std::pair<wifi_error, std::vector<wifi_ring_buffer_status>> getRingBuffersStatus(
             const std::string& iface_name);
@@ -637,7 +637,7 @@
     virtual wifi_error createVirtualInterface(const std::string& ifname,
                                               wifi_interface_type iftype);
     virtual wifi_error deleteVirtualInterface(const std::string& ifname);
-    wifi_error getSupportedIfaceName(uint32_t iface_type, std::string& ifname);
+    virtual wifi_error getSupportedIfaceName(uint32_t iface_type, std::string& ifname);
 
     // STA + STA functions
     virtual wifi_error multiStaSetPrimaryConnection(const std::string& ifname);
diff --git a/wifi/1.6/vts/OWNERS b/wifi/1.6/vts/OWNERS
new file mode 100644
index 0000000..294fc82
--- /dev/null
+++ b/wifi/1.6/vts/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 33618
+include ../../1.0/vts/OWNERS
diff --git a/wifi/1.6/vts/functional/Android.bp b/wifi/1.6/vts/functional/Android.bp
new file mode 100644
index 0000000..2d126c7
--- /dev/null
+++ b/wifi/1.6/vts/functional/Android.bp
@@ -0,0 +1,98 @@
+//
+// 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_test {
+    name: "VtsHalWifiV1_6TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "wifi_chip_hidl_test.cpp",
+        "wifi_sta_iface_hidl_test.cpp",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+        "android.hardware.wifi@1.5",
+        "android.hardware.wifi@1.6",
+        "libwifi-system-iface",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+// These tests are split out so that they can be conditioned on presence of the
+// "android.hardware.wifi.rtt" feature.
+cc_test {
+    name: "VtsHalWifiRttV1_6TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "wifi_rtt_controller_hidl_test.cpp",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+        "android.hardware.wifi@1.5",
+        "android.hardware.wifi@1.6",
+        "libwifi-system-iface",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+// These tests are split out so that they can be conditioned on presence of the
+// "android.hardware.wifi.aware" feature.
+cc_test {
+    name: "VtsHalWifiNanV1_6TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "wifi_nan_iface_hidl_test.cpp",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+        "android.hardware.wifi@1.5",
+        "android.hardware.wifi@1.6",
+        "libwifi-system-iface",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/wifi/1.6/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.6/vts/functional/wifi_chip_hidl_test.cpp
new file mode 100644
index 0000000..7c5b7e6
--- /dev/null
+++ b/wifi/1.6/vts/functional/wifi_chip_hidl_test.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/logging.h>
+
+#undef NAN  // NAN is defined in bionic/libc/include/math.h:38
+
+#include <android/hardware/wifi/1.4/IWifiChipEventCallback.h>
+#include <android/hardware/wifi/1.6/IWifi.h>
+#include <android/hardware/wifi/1.6/IWifiChip.h>
+#include <android/hardware/wifi/1.6/IWifiStaIface.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "wifi_hidl_call_util.h"
+#include "wifi_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::V1_0::ChipModeId;
+using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifiIface;
+using ::android::hardware::wifi::V1_0::IWifiStaIface;
+using ::android::hardware::wifi::V1_0::WifiDebugRingBufferStatus;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_4::IWifiChipEventCallback;
+using ::android::hardware::wifi::V1_5::WifiBand;
+using ::android::hardware::wifi::V1_5::WifiIfaceMode;
+using ::android::hardware::wifi::V1_6::IWifiChip;
+
+/**
+ * Fixture to use for all Wifi chip HIDL interface tests.
+ */
+class WifiChipHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
+        wifi_chip_ = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
+        ASSERT_NE(nullptr, wifi_chip_.get());
+    }
+
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+  protected:
+    // Helper function to configure the Chip in one of the supported modes.
+    // Most of the non-mode-configuration-related methods require chip
+    // to be first configured.
+    ChipModeId configureChipForIfaceType(IfaceType type, bool expectSuccess) {
+        ChipModeId mode_id;
+        EXPECT_EQ(expectSuccess, configureChipToSupportIfaceType(wifi_chip_, type, &mode_id));
+        return mode_id;
+    }
+
+    sp<IWifiChip> wifi_chip_;
+
+  private:
+    std::string GetInstanceName() { return GetParam(); }
+};
+
+/* getUsableChannels_1_6:
+ * Ensure that a call to getUsableChannels_1_6 will return with a success
+ * status for valid inputs.
+ */
+TEST_P(WifiChipHidlTest, getUsableChannels_1_6) {
+    uint32_t ifaceModeMask =
+            WifiIfaceMode::IFACE_MODE_P2P_CLIENT | WifiIfaceMode::IFACE_MODE_P2P_GO;
+    uint32_t filterMask = IWifiChip::UsableChannelFilter::CELLULAR_COEXISTENCE |
+                          IWifiChip::UsableChannelFilter::CONCURRENCY;
+    configureChipForIfaceType(IfaceType::STA, true);
+    WifiBand band = WifiBand::BAND_24GHZ_5GHZ_6GHZ;
+    const auto& statusNonEmpty =
+            HIDL_INVOKE(wifi_chip_, getUsableChannels_1_6, band, ifaceModeMask, filterMask);
+    if (statusNonEmpty.first.code == WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        GTEST_SKIP() << "Skipping this test since getUsableChannels() is not supported by vendor.";
+    }
+
+    EXPECT_EQ(WifiStatusCode::SUCCESS, statusNonEmpty.first.code);
+}
+
+/* getAvailableModes_1_6:
+ * Ensures that a call to getAvailableModes_1_6 will return with a success status code.
+ */
+TEST_P(WifiChipHidlTest, getAvailableModes_1_6) {
+    const auto& status_and_modes = HIDL_INVOKE(wifi_chip_, getAvailableModes_1_6);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_modes.first.code);
+    EXPECT_LT(0u, status_and_modes.second.size());
+}
+
+/*
+ * getSupportedRadioCombinationsMatrix:
+ * Ensure that a call to getSupportedRadioCombinationsMatrix will return
+ * with a success status code.
+ */
+TEST_P(WifiChipHidlTest, getSupportedRadioCombinationsMatrix) {
+    configureChipForIfaceType(IfaceType::STA, true);
+    const auto& statusNonEmpty = HIDL_INVOKE(wifi_chip_, getSupportedRadioCombinationsMatrix);
+    if (statusNonEmpty.first.code == WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        GTEST_SKIP() << "Skipping this test since getSupportedRadioCombinationsMatrix() is not "
+                        "supported by vendor.";
+    }
+
+    EXPECT_EQ(WifiStatusCode::SUCCESS, statusNonEmpty.first.code);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, WifiChipHidlTest,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 ::android::hardware::wifi::V1_6::IWifi::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.6/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.6/vts/functional/wifi_nan_iface_hidl_test.cpp
new file mode 100644
index 0000000..7bcc6d3
--- /dev/null
+++ b/wifi/1.6/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -0,0 +1,795 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Nanache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.6/IWifi.h>
+#include <android/hardware/wifi/1.6/IWifiNanIface.h>
+#include <android/hardware/wifi/1.6/IWifiNanIfaceEventCallback.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <vector>
+
+#include "wifi_hidl_call_util.h"
+#include "wifi_hidl_test_utils.h"
+
+using namespace ::android::hardware::wifi::V1_0;
+using namespace ::android::hardware::wifi::V1_2;
+using namespace ::android::hardware::wifi::V1_4;
+using namespace ::android::hardware::wifi::V1_5;
+using namespace ::android::hardware::wifi::V1_6;
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+#define TIMEOUT_PERIOD 10
+
+android::sp<android::hardware::wifi::V1_6::IWifiNanIface> getWifiNanIface_1_6(
+        const std::string& instance_name) {
+    return android::hardware::wifi::V1_6::IWifiNanIface::castFrom(getWifiNanIface(instance_name));
+}
+
+/**
+ * Fixture to use for all NAN Iface HIDL interface tests.
+ */
+class WifiNanIfaceHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        if (!::testing::deviceSupportsFeature("android.hardware.wifi.aware"))
+            GTEST_SKIP() << "Skipping this test since NAN is not supported.";
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
+        iwifiNanIface = getWifiNanIface_1_6(GetInstanceName());
+        ASSERT_NE(nullptr, iwifiNanIface.get());
+        ASSERT_EQ(WifiStatusCode::SUCCESS, HIDL_INVOKE(iwifiNanIface, registerEventCallback_1_6,
+                                                       new WifiNanIfaceEventCallback(*this))
+                                                   .code);
+    }
+
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+    /* Used as a mechanism to inform the test about data/event callback */
+    inline void notify() {
+        std::unique_lock<std::mutex> lock(mtx_);
+        count_++;
+        cv_.notify_one();
+    }
+
+    enum CallbackType {
+        INVALID = -2,
+        ANY_CALLBACK = -1,
+
+        NOTIFY_CAPABILITIES_RESPONSE = 0,
+        NOTIFY_ENABLE_RESPONSE,
+        NOTIFY_CONFIG_RESPONSE,
+        NOTIFY_DISABLE_RESPONSE,
+        NOTIFY_START_PUBLISH_RESPONSE,
+        NOTIFY_STOP_PUBLISH_RESPONSE,
+        NOTIFY_START_SUBSCRIBE_RESPONSE,
+        NOTIFY_STOP_SUBSCRIBE_RESPONSE,
+        NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE,
+        NOTIFY_CREATE_DATA_INTERFACE_RESPONSE,
+        NOTIFY_DELETE_DATA_INTERFACE_RESPONSE,
+        NOTIFY_INITIATE_DATA_PATH_RESPONSE,
+        NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE,
+        NOTIFY_TERMINATE_DATA_PATH_RESPONSE,
+        NOTIFY_CAPABILITIES_RESPONSE_1_5,
+        NOTIFY_CAPABILITIES_RESPONSE_1_6,
+
+        EVENT_CLUSTER_EVENT,
+        EVENT_DISABLED,
+        EVENT_PUBLISH_TERMINATED,
+        EVENT_SUBSCRIBE_TERMINATED,
+        EVENT_MATCH,
+        EVENT_MATCH_EXPIRED,
+        EVENT_FOLLOWUP_RECEIVED,
+        EVENT_TRANSMIT_FOLLOWUP,
+        EVENT_DATA_PATH_REQUEST,
+        EVENT_DATA_PATH_CONFIRM,
+        EVENT_DATA_PATH_TERMINATED,
+        EVENT_DATA_PATH_CONFIRM_1_2,
+        EVENT_DATA_PATH_SCHEDULE_UPDATE,
+        EVENT_MATCH_1_6,
+        EVENT_DATA_PATH_SCHEDULE_UPDATE_1_6,
+        EVENT_DATA_PATH_CONFIRM_1_6,
+    };
+
+    /* Test code calls this function to wait for data/event callback */
+    /* Must set callbackType = INVALID before call this function */
+    inline std::cv_status wait(CallbackType waitForCallbackType) {
+        std::unique_lock<std::mutex> lock(mtx_);
+
+        EXPECT_NE(INVALID, waitForCallbackType);  // can't ASSERT in a
+                                                  // non-void-returning method
+
+        std::cv_status status = std::cv_status::no_timeout;
+        auto now = std::chrono::system_clock::now();
+        while (count_ == 0) {
+            status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+            if (status == std::cv_status::timeout) return status;
+            if (waitForCallbackType != ANY_CALLBACK && callbackType != INVALID &&
+                callbackType != waitForCallbackType) {
+                count_--;
+            }
+        }
+        count_--;
+        return status;
+    }
+
+    class WifiNanIfaceEventCallback
+        : public ::android::hardware::wifi::V1_6::IWifiNanIfaceEventCallback {
+        WifiNanIfaceHidlTest& parent_;
+
+      public:
+        WifiNanIfaceEventCallback(WifiNanIfaceHidlTest& parent) : parent_(parent){};
+
+        virtual ~WifiNanIfaceEventCallback() = default;
+
+        Return<void> notifyCapabilitiesResponse(
+                uint16_t id, const WifiNanStatus& status,
+                const ::android::hardware::wifi::V1_0::NanCapabilities& capabilities) override {
+            parent_.callbackType = NOTIFY_CAPABILITIES_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+            parent_.capabilities = capabilities;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyCapabilitiesResponse_1_5(
+                uint16_t id, const WifiNanStatus& status,
+                const ::android::hardware::wifi::V1_5::NanCapabilities& capabilities) override {
+            parent_.callbackType = NOTIFY_CAPABILITIES_RESPONSE_1_5;
+
+            parent_.id = id;
+            parent_.status = status;
+            parent_.capabilities_1_5 = capabilities;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyEnableResponse(uint16_t id, const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_ENABLE_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyConfigResponse(uint16_t id, const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_CONFIG_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyDisableResponse(uint16_t id, const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_DISABLE_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyStartPublishResponse(uint16_t id, const WifiNanStatus& status,
+                                                uint8_t sessionId) override {
+            parent_.callbackType = NOTIFY_START_PUBLISH_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+            parent_.sessionId = sessionId;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyStopPublishResponse(uint16_t id, const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_STOP_PUBLISH_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyStartSubscribeResponse(uint16_t id, const WifiNanStatus& status,
+                                                  uint8_t sessionId) override {
+            parent_.callbackType = NOTIFY_START_SUBSCRIBE_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+            parent_.sessionId = sessionId;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyStopSubscribeResponse(uint16_t id,
+                                                 const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_STOP_SUBSCRIBE_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyTransmitFollowupResponse(uint16_t id,
+                                                    const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyCreateDataInterfaceResponse(uint16_t id,
+                                                       const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_CREATE_DATA_INTERFACE_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyDeleteDataInterfaceResponse(uint16_t id,
+                                                       const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_DELETE_DATA_INTERFACE_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyInitiateDataPathResponse(uint16_t id, const WifiNanStatus& status,
+                                                    uint32_t ndpInstanceId) override {
+            parent_.callbackType = NOTIFY_INITIATE_DATA_PATH_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+            parent_.ndpInstanceId = ndpInstanceId;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyRespondToDataPathIndicationResponse(
+                uint16_t id, const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyTerminateDataPathResponse(uint16_t id,
+                                                     const WifiNanStatus& status) override {
+            parent_.callbackType = NOTIFY_TERMINATE_DATA_PATH_RESPONSE;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventClusterEvent(const NanClusterEventInd& event) override {
+            parent_.callbackType = EVENT_CLUSTER_EVENT;
+
+            parent_.nanClusterEventInd = event;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventDisabled(const WifiNanStatus& status) override {
+            parent_.callbackType = EVENT_DISABLED;
+
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventPublishTerminated(uint8_t sessionId,
+                                            const WifiNanStatus& status) override {
+            parent_.callbackType = EVENT_PUBLISH_TERMINATED;
+
+            parent_.sessionId = sessionId;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventSubscribeTerminated(uint8_t sessionId,
+                                              const WifiNanStatus& status) override {
+            parent_.callbackType = EVENT_SUBSCRIBE_TERMINATED;
+
+            parent_.sessionId = sessionId;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventMatch(
+                const ::android::hardware::wifi::V1_0::NanMatchInd& event) override {
+            parent_.callbackType = EVENT_MATCH;
+
+            parent_.nanMatchInd = event;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventMatchExpired(uint8_t discoverySessionId, uint32_t peerId) override {
+            parent_.callbackType = EVENT_MATCH_EXPIRED;
+
+            parent_.sessionId = discoverySessionId;
+            parent_.peerId = peerId;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventFollowupReceived(const NanFollowupReceivedInd& event) override {
+            parent_.callbackType = EVENT_FOLLOWUP_RECEIVED;
+
+            parent_.nanFollowupReceivedInd = event;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventTransmitFollowup(uint16_t id, const WifiNanStatus& status) override {
+            parent_.callbackType = EVENT_TRANSMIT_FOLLOWUP;
+
+            parent_.id = id;
+            parent_.status = status;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventDataPathRequest(const NanDataPathRequestInd& event) override {
+            parent_.callbackType = EVENT_DATA_PATH_REQUEST;
+
+            parent_.nanDataPathRequestInd = event;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventDataPathConfirm(
+                const ::android::hardware::wifi::V1_0::NanDataPathConfirmInd& event) override {
+            parent_.callbackType = EVENT_DATA_PATH_CONFIRM;
+
+            parent_.nanDataPathConfirmInd = event;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventDataPathTerminated(uint32_t ndpInstanceId) override {
+            parent_.callbackType = EVENT_DATA_PATH_TERMINATED;
+
+            parent_.ndpInstanceId = ndpInstanceId;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventDataPathConfirm_1_2(
+                const ::android::hardware::wifi::V1_2::NanDataPathConfirmInd& event) override {
+            parent_.callbackType = EVENT_DATA_PATH_CONFIRM_1_2;
+
+            parent_.nanDataPathConfirmInd_1_2 = event;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventDataPathScheduleUpdate(
+                const ::android::hardware::wifi::V1_2::NanDataPathScheduleUpdateInd& event)
+                override {
+            parent_.callbackType = EVENT_DATA_PATH_SCHEDULE_UPDATE;
+
+            parent_.nanDataPathScheduleUpdateInd_1_2 = event;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventMatch_1_6(
+                const ::android::hardware::wifi::V1_6::NanMatchInd& event) override {
+            parent_.callbackType = EVENT_MATCH_1_6;
+
+            parent_.nanMatchInd_1_6 = event;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> notifyCapabilitiesResponse_1_6(
+                uint16_t id, const WifiNanStatus& status,
+                const ::android::hardware::wifi::V1_6::NanCapabilities& capabilities) override {
+            parent_.callbackType = NOTIFY_CAPABILITIES_RESPONSE_1_6;
+
+            parent_.id = id;
+            parent_.status = status;
+            parent_.capabilities_1_6 = capabilities;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventDataPathScheduleUpdate_1_6(
+                const ::android::hardware::wifi::V1_6::NanDataPathScheduleUpdateInd& event)
+                override {
+            parent_.callbackType = EVENT_DATA_PATH_SCHEDULE_UPDATE_1_6;
+
+            parent_.nanDataPathScheduleUpdateInd_1_6 = event;
+
+            parent_.notify();
+            return Void();
+        }
+
+        Return<void> eventDataPathConfirm_1_6(
+                const ::android::hardware::wifi::V1_6::NanDataPathConfirmInd& event) override {
+            parent_.callbackType = EVENT_DATA_PATH_CONFIRM_1_6;
+
+            parent_.nanDataPathConfirmInd_1_6 = event;
+
+            parent_.notify();
+            return Void();
+        }
+    };
+
+  private:
+    // synchronization objects
+    std::mutex mtx_;
+    std::condition_variable cv_;
+    int count_ = 0;
+
+  protected:
+    android::sp<::android::hardware::wifi::V1_6::IWifiNanIface> iwifiNanIface;
+
+    // Data from IWifiNanIfaceEventCallback callbacks: this is the collection of
+    // all arguments to all callbacks. They are set by the callback
+    // (notifications or events) and can be retrieved by tests.
+    CallbackType callbackType;
+    uint16_t id;
+    WifiNanStatus status;
+    uint8_t sessionId;
+    uint32_t ndpInstanceId;
+    NanClusterEventInd nanClusterEventInd;
+    ::android::hardware::wifi::V1_0::NanMatchInd nanMatchInd;
+    ::android::hardware::wifi::V1_6::NanMatchInd nanMatchInd_1_6;
+    uint32_t peerId;
+    NanFollowupReceivedInd nanFollowupReceivedInd;
+    NanDataPathRequestInd nanDataPathRequestInd;
+    ::android::hardware::wifi::V1_0::NanCapabilities capabilities;
+    ::android::hardware::wifi::V1_5::NanCapabilities capabilities_1_5;
+    ::android::hardware::wifi::V1_6::NanCapabilities capabilities_1_6;
+    ::android::hardware::wifi::V1_0::NanDataPathConfirmInd nanDataPathConfirmInd;
+    ::android::hardware::wifi::V1_2::NanDataPathConfirmInd nanDataPathConfirmInd_1_2;
+    ::android::hardware::wifi::V1_6::NanDataPathConfirmInd nanDataPathConfirmInd_1_6;
+    ::android::hardware::wifi::V1_2::NanDataPathScheduleUpdateInd nanDataPathScheduleUpdateInd_1_2;
+    ::android::hardware::wifi::V1_6::NanDataPathScheduleUpdateInd nanDataPathScheduleUpdateInd_1_6;
+
+    std::string GetInstanceName() { return GetParam(); }
+};
+
+/*
+ * Create:
+ * Ensures that an instance of the IWifiNanIface proxy object is
+ * successfully created.
+ */
+TEST_P(WifiNanIfaceHidlTest, Create) {
+    // The creation of a proxy object is tested as part of SetUp method.
+}
+
+/*
+ * enableRequest_1_6InvalidArgs: validate that fails with invalid arguments
+ */
+TEST_P(WifiNanIfaceHidlTest, enableRequest_1_6InvalidArgs) {
+    uint16_t inputCmdId = 10;
+    callbackType = INVALID;
+    ::android::hardware::wifi::V1_4::NanEnableRequest nanEnableRequest = {};
+    ::android::hardware::wifi::V1_6::NanConfigRequestSupplemental nanConfigRequestSupp = {};
+    const auto& halStatus = HIDL_INVOKE(iwifiNanIface, enableRequest_1_6, inputCmdId,
+                                        nanEnableRequest, nanConfigRequestSupp);
+    if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        ASSERT_EQ(WifiStatusCode::SUCCESS, halStatus.code);
+
+        // wait for a callback
+        ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
+        ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callbackType);
+        ASSERT_EQ(id, inputCmdId);
+        ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+    }
+}
+
+/*
+ * enableRequest_1_6ShimInvalidArgs: validate that fails with invalid arguments
+ * to the shim
+ */
+TEST_P(WifiNanIfaceHidlTest, enableRequest_1_6ShimInvalidArgs) {
+    uint16_t inputCmdId = 10;
+    ::android::hardware::wifi::V1_4::NanEnableRequest nanEnableRequest = {};
+    nanEnableRequest.configParams.numberOfPublishServiceIdsInBeacon = 128;  // must be <= 127
+    ::android::hardware::wifi::V1_6::NanConfigRequestSupplemental nanConfigRequestSupp = {};
+    const auto& halStatus = HIDL_INVOKE(iwifiNanIface, enableRequest_1_6, inputCmdId,
+                                        nanEnableRequest, nanConfigRequestSupp);
+    if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, halStatus.code);
+    }
+}
+
+/*
+ * configRequest_1_6InvalidArgs: validate that fails with invalid arguments
+ */
+TEST_P(WifiNanIfaceHidlTest, configRequest_1_6InvalidArgs) {
+    uint16_t inputCmdId = 10;
+    callbackType = INVALID;
+    ::android::hardware::wifi::V1_4::NanConfigRequest nanConfigRequest = {};
+    ::android::hardware::wifi::V1_6::NanConfigRequestSupplemental nanConfigRequestSupp = {};
+    const auto& halStatus = HIDL_INVOKE(iwifiNanIface, configRequest_1_6, inputCmdId,
+                                        nanConfigRequest, nanConfigRequestSupp);
+
+    if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        ASSERT_EQ(WifiStatusCode::SUCCESS, halStatus.code);
+
+        // wait for a callback
+        ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE));
+        ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callbackType);
+        ASSERT_EQ(id, inputCmdId);
+        ASSERT_EQ(status.status, NanStatusType::INVALID_ARGS);
+    }
+}
+
+/*
+ * configRequest_1_6ShimInvalidArgs: validate that fails with invalid arguments
+ * to the shim
+ */
+TEST_P(WifiNanIfaceHidlTest, configRequest_1_6ShimInvalidArgs) {
+    uint16_t inputCmdId = 10;
+    ::android::hardware::wifi::V1_4::NanConfigRequest nanConfigRequest = {};
+    nanConfigRequest.numberOfPublishServiceIdsInBeacon = 128;  // must be <= 127
+    ::android::hardware::wifi::V1_6::NanConfigRequestSupplemental nanConfigRequestSupp = {};
+    const auto& halStatus = HIDL_INVOKE(iwifiNanIface, configRequest_1_6, inputCmdId,
+                                        nanConfigRequest, nanConfigRequestSupp);
+    if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, halStatus.code);
+    }
+}
+
+/*
+ * notifyCapabilitiesResponse_1_6: validate that returns capabilities.
+ */
+TEST_P(WifiNanIfaceHidlTest, notifyCapabilitiesResponse_1_6) {
+    uint16_t inputCmdId = 10;
+    callbackType = INVALID;
+    const auto& halStatus = HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest_1_5, inputCmdId).code;
+    ASSERT_EQ(WifiStatusCode::SUCCESS, halStatus);
+    // wait for a callback
+    ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE_1_6));
+    ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE_1_6, callbackType);
+    ASSERT_EQ(id, inputCmdId);
+    ASSERT_EQ(status.status, NanStatusType::SUCCESS);
+
+    // check for reasonable capability values
+    EXPECT_GT(capabilities_1_6.maxConcurrentClusters, (unsigned int)0);
+    EXPECT_GT(capabilities_1_6.maxPublishes, (unsigned int)0);
+    EXPECT_GT(capabilities_1_6.maxSubscribes, (unsigned int)0);
+    EXPECT_EQ(capabilities_1_6.maxServiceNameLen, (unsigned int)255);
+    EXPECT_EQ(capabilities_1_6.maxMatchFilterLen, (unsigned int)255);
+    EXPECT_GT(capabilities_1_6.maxTotalMatchFilterLen, (unsigned int)255);
+    EXPECT_EQ(capabilities_1_6.maxServiceSpecificInfoLen, (unsigned int)255);
+    EXPECT_GE(capabilities_1_6.maxExtendedServiceSpecificInfoLen, (unsigned int)255);
+    EXPECT_GT(capabilities_1_6.maxNdiInterfaces, (unsigned int)0);
+    EXPECT_GT(capabilities_1_6.maxNdpSessions, (unsigned int)0);
+    EXPECT_GT(capabilities_1_6.maxAppInfoLen, (unsigned int)0);
+    EXPECT_GT(capabilities_1_6.maxQueuedTransmitFollowupMsgs, (unsigned int)0);
+    EXPECT_GT(capabilities_1_6.maxSubscribeInterfaceAddresses, (unsigned int)0);
+    EXPECT_NE(capabilities_1_6.supportedCipherSuites, (unsigned int)0);
+    EXPECT_TRUE(capabilities_1_6.instantCommunicationModeSupportFlag ||
+                !capabilities_1_6.instantCommunicationModeSupportFlag);
+}
+
+/*
+ * startPublishRequest_1_6: validate that success with valid arguments
+ */
+TEST_P(WifiNanIfaceHidlTest, startPublishRequest_1_6) {
+    uint16_t inputCmdId = 10;
+    ::android::hardware::wifi::V1_0::NanBandSpecificConfig config24 = {};
+    config24.rssiClose = 60;
+    config24.rssiMiddle = 70;
+    config24.rssiCloseProximity = 60;
+    config24.dwellTimeMs = 200;
+    config24.scanPeriodSec = 20;
+    config24.validDiscoveryWindowIntervalVal = false;
+    config24.discoveryWindowIntervalVal = 0;
+
+    ::android::hardware::wifi::V1_0::NanBandSpecificConfig config5 = {};
+    config5.rssiClose = 60;
+    config5.rssiMiddle = 75;
+    config5.rssiCloseProximity = 60;
+    config5.dwellTimeMs = 200;
+    config5.scanPeriodSec = 20;
+    config5.validDiscoveryWindowIntervalVal = false;
+    config5.discoveryWindowIntervalVal = 0;
+    ::android::hardware::wifi::V1_4::NanEnableRequest req = {};
+    req.operateInBand[(size_t)::android::hardware::wifi::V1_4::NanBandIndex::NAN_BAND_24GHZ] = true;
+    req.operateInBand[(size_t)::android::hardware::wifi::V1_4::NanBandIndex::NAN_BAND_5GHZ] = false;
+    req.hopCountMax = 2;
+    req.configParams.masterPref = 0;
+    req.configParams.disableDiscoveryAddressChangeIndication = true;
+    req.configParams.disableStartedClusterIndication = true;
+    req.configParams.disableJoinedClusterIndication = true;
+    req.configParams.includePublishServiceIdsInBeacon = true;
+    req.configParams.numberOfPublishServiceIdsInBeacon = 0;
+    req.configParams.includeSubscribeServiceIdsInBeacon = true;
+    req.configParams.numberOfSubscribeServiceIdsInBeacon = 0;
+    req.configParams.rssiWindowSize = 8;
+    req.configParams.macAddressRandomizationIntervalSec = 1800;
+    req.configParams.bandSpecificConfig[(
+            size_t)::android::hardware::wifi::V1_4::NanBandIndex::NAN_BAND_24GHZ] = config24;
+    req.configParams.bandSpecificConfig[(
+            size_t)::android::hardware::wifi::V1_4::NanBandIndex::NAN_BAND_5GHZ] = config5;
+
+    req.debugConfigs.validClusterIdVals = true;
+    req.debugConfigs.clusterIdTopRangeVal = 65535;
+    req.debugConfigs.clusterIdBottomRangeVal = 0;
+    req.debugConfigs.validIntfAddrVal = false;
+    req.debugConfigs.validOuiVal = false;
+    req.debugConfigs.ouiVal = 0;
+    req.debugConfigs.validRandomFactorForceVal = false;
+    req.debugConfigs.randomFactorForceVal = 0;
+    req.debugConfigs.validHopCountForceVal = false;
+    req.debugConfigs.hopCountForceVal = 0;
+    req.debugConfigs.validDiscoveryChannelVal = false;
+    req.debugConfigs.discoveryChannelMhzVal[(
+            size_t)::android::hardware::wifi::V1_4::NanBandIndex::NAN_BAND_24GHZ] = 0;
+    req.debugConfigs.discoveryChannelMhzVal[(
+            size_t)::android::hardware::wifi::V1_4::NanBandIndex::NAN_BAND_5GHZ] = 0;
+    req.debugConfigs.validUseBeaconsInBandVal = false;
+    req.debugConfigs.useBeaconsInBandVal[(
+            size_t)::android::hardware::wifi::V1_4::NanBandIndex::NAN_BAND_24GHZ] = true;
+    req.debugConfigs.useBeaconsInBandVal[(
+            size_t)::android::hardware::wifi::V1_4::NanBandIndex::NAN_BAND_5GHZ] = true;
+    req.debugConfigs.validUseSdfInBandVal = false;
+    req.debugConfigs.useSdfInBandVal[(
+            size_t)::android::hardware::wifi::V1_4::NanBandIndex::NAN_BAND_24GHZ] = true;
+    req.debugConfigs
+            .useSdfInBandVal[(size_t)::android::hardware::wifi::V1_4::NanBandIndex::NAN_BAND_5GHZ] =
+            true;
+
+    ::android::hardware::wifi::V1_6::NanConfigRequestSupplemental nanConfigRequestSupp = {};
+    nanConfigRequestSupp.V1_5.V1_2.discoveryBeaconIntervalMs = 20;
+    nanConfigRequestSupp.V1_5.V1_2.numberOfSpatialStreamsInDiscovery = 0;
+    nanConfigRequestSupp.V1_5.V1_2.enableDiscoveryWindowEarlyTermination = false;
+
+    callbackType = INVALID;
+
+    const auto& halStatus =
+            HIDL_INVOKE(iwifiNanIface, enableRequest_1_6, inputCmdId, req, nanConfigRequestSupp);
+    if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        ASSERT_EQ(WifiStatusCode::SUCCESS, halStatus.code);
+
+        // wait for a callback
+        ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
+        ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callbackType);
+        ASSERT_EQ(id, inputCmdId);
+        ASSERT_EQ(status.status, NanStatusType::SUCCESS);
+    }
+    ::android::hardware::wifi::V1_6::NanPublishRequest nanPublishRequest = {};
+    nanPublishRequest.baseConfigs.sessionId = 0;
+    nanPublishRequest.baseConfigs.ttlSec = 0;
+    nanPublishRequest.baseConfigs.discoveryWindowPeriod = 1;
+    nanPublishRequest.baseConfigs.discoveryCount = 0;
+    nanPublishRequest.baseConfigs.serviceName = {97};
+
+    nanPublishRequest.baseConfigs.discoveryMatchIndicator = NanMatchAlg::MATCH_NEVER;
+    nanPublishRequest.baseConfigs.useRssiThreshold = false;
+    nanPublishRequest.baseConfigs.disableDiscoveryTerminationIndication = false;
+    nanPublishRequest.baseConfigs.disableMatchExpirationIndication = true;
+    nanPublishRequest.baseConfigs.disableFollowupReceivedIndication = false;
+    nanPublishRequest.baseConfigs.securityConfig.securityType = NanDataPathSecurityType::OPEN;
+    nanPublishRequest.autoAcceptDataPathRequests = false;
+    nanPublishRequest.publishType = NanPublishType::UNSOLICITED;
+    nanPublishRequest.txType = NanTxType::BROADCAST;
+
+    const auto& halStatus1 =
+            HIDL_INVOKE(iwifiNanIface, startPublishRequest_1_6, inputCmdId + 1, nanPublishRequest);
+
+    if (halStatus1.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        ASSERT_EQ(WifiStatusCode::SUCCESS, halStatus1.code);
+
+        // wait for a callback
+        ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_START_PUBLISH_RESPONSE));
+        ASSERT_EQ(NOTIFY_START_PUBLISH_RESPONSE, callbackType);
+        ASSERT_EQ(id, inputCmdId + 1);
+        ASSERT_EQ(status.status, NanStatusType::SUCCESS);
+    }
+}
+
+/*
+ * respondToDataPathIndicationRequest_1_6InvalidArgs: validate that fails with invalid arguments
+ */
+TEST_P(WifiNanIfaceHidlTest, respondToDataPathIndicationRequest_1_6ShimInvalidArgs) {
+    uint16_t inputCmdId = 10;
+    callbackType = INVALID;
+    ::android::hardware::wifi::V1_6::NanRespondToDataPathIndicationRequest
+            nanRespondToDataPathIndicationRequest = {};
+    nanRespondToDataPathIndicationRequest.ifaceName = "AwareinterfaceNameTooLong";
+    const auto& halStatus = HIDL_INVOKE(iwifiNanIface, respondToDataPathIndicationRequest_1_6,
+                                        inputCmdId, nanRespondToDataPathIndicationRequest);
+
+    if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, halStatus.code);
+    }
+}
+
+/*
+ * initiateDataPathRequest_1_6InvalidArgs: validate that fails with invalid arguments
+ */
+TEST_P(WifiNanIfaceHidlTest, initiateDataPathRequest_1_6ShimInvalidArgs) {
+    uint16_t inputCmdId = 10;
+    callbackType = INVALID;
+    ::android::hardware::wifi::V1_6::NanInitiateDataPathRequest nanInitiateDataPathRequest = {};
+    nanInitiateDataPathRequest.ifaceName = "AwareinterfaceNameTooLong";
+    const auto& halStatus = HIDL_INVOKE(iwifiNanIface, initiateDataPathRequest_1_6, inputCmdId,
+                                        nanInitiateDataPathRequest);
+
+    if (halStatus.code != WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        ASSERT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, halStatus.code);
+    }
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiNanIfaceHidlTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, WifiNanIfaceHidlTest,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 ::android::hardware::wifi::V1_6::IWifi::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.6/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.6/vts/functional/wifi_rtt_controller_hidl_test.cpp
new file mode 100644
index 0000000..5b5e623
--- /dev/null
+++ b/wifi/1.6/vts/functional/wifi_rtt_controller_hidl_test.cpp
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/logging.h>
+
+#undef NAN  // NAN is defined in bionic/libc/include/math.h:38
+
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.6/IWifi.h>
+#include <android/hardware/wifi/1.6/IWifiChip.h>
+#include <android/hardware/wifi/1.6/IWifiRttController.h>
+#include <android/hardware/wifi/1.6/IWifiRttControllerEventCallback.h>
+#include <android/hardware/wifi/1.6/IWifiStaIface.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "wifi_hidl_call_util.h"
+#include "wifi_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::V1_0::CommandId;
+using ::android::hardware::wifi::V1_0::RttPeerType;
+using ::android::hardware::wifi::V1_0::RttType;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_6::IWifiChip;
+using ::android::hardware::wifi::V1_6::IWifiRttController;
+using ::android::hardware::wifi::V1_6::IWifiRttControllerEventCallback;
+using ::android::hardware::wifi::V1_6::IWifiStaIface;
+using ::android::hardware::wifi::V1_6::RttBw;
+using ::android::hardware::wifi::V1_6::RttCapabilities;
+using ::android::hardware::wifi::V1_6::RttConfig;
+using ::android::hardware::wifi::V1_6::RttPreamble;
+using ::android::hardware::wifi::V1_6::RttResponder;
+using ::android::hardware::wifi::V1_6::RttResult;
+using ::android::hardware::wifi::V1_6::WifiChannelInfo;
+using ::android::hardware::wifi::V1_6::WifiChannelWidthInMhz;
+
+/**
+ * Fixture to use for all RTT controller HIDL interface tests.
+ */
+class WifiRttControllerHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        if (!::testing::deviceSupportsFeature("android.hardware.wifi.rtt"))
+            GTEST_SKIP() << "Skipping this test since RTT is not supported.";
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
+        wifi_rtt_controller_ = getWifiRttController();
+        ASSERT_NE(nullptr, wifi_rtt_controller_.get());
+
+        // Check RTT support before we run the test.
+        std::pair<WifiStatus, RttCapabilities> status_and_caps;
+        status_and_caps = HIDL_INVOKE(wifi_rtt_controller_, getCapabilities_1_6);
+        if (status_and_caps.first.code == WifiStatusCode::ERROR_NOT_SUPPORTED) {
+            GTEST_SKIP() << "Skipping this test since RTT is not supported.";
+        }
+    }
+
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+    // A simple test implementation of WifiRttControllerEventCallback.
+    class WifiRttControllerEventCallback
+        : public ::testing::VtsHalHidlTargetCallbackBase<WifiRttControllerHidlTest>,
+          public IWifiRttControllerEventCallback {
+      public:
+        WifiRttControllerEventCallback(){};
+
+        virtual ~WifiRttControllerEventCallback() = default;
+
+        Return<void> onResults(CommandId cmdId __unused,
+                               const hidl_vec<::android::hardware::wifi::V1_0::RttResult>& results
+                                       __unused) {
+            return Void();
+        };
+
+        Return<void> onResults_1_4(
+                CommandId cmdId __unused,
+                const hidl_vec<::android::hardware::wifi::V1_4::RttResult>& results __unused) {
+            return Void();
+        };
+
+        Return<void> onResults_1_6(CommandId cmdId __unused,
+                                   const hidl_vec<RttResult>& results __unused) {
+            return Void();
+        };
+    };
+
+  protected:
+    sp<IWifiRttController> wifi_rtt_controller_;
+
+  private:
+    std::string GetInstanceName() { return GetParam(); }
+
+    sp<IWifiRttController> getWifiRttController() {
+        const std::string& instance_name = GetInstanceName();
+
+        sp<IWifiChip> wifi_chip = IWifiChip::castFrom(getWifiChip(instance_name));
+        EXPECT_NE(nullptr, wifi_chip.get());
+
+        sp<IWifiStaIface> wifi_sta_iface = IWifiStaIface::castFrom(getWifiStaIface(instance_name));
+        EXPECT_NE(nullptr, wifi_sta_iface.get());
+
+        const auto& status_and_controller =
+                HIDL_INVOKE(wifi_chip, createRttController_1_6, wifi_sta_iface);
+        EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_controller.first.code);
+        EXPECT_NE(nullptr, status_and_controller.second.get());
+
+        return status_and_controller.second.get();
+    }
+};
+
+/*
+ * registerEventCallback_1_6
+ * This test case tests the registerEventCallback_1_6() API which registers
+ * a call back function with the hal implementation
+ *
+ * Note: it is not feasible to test the invocation of the call back function
+ * since event is triggered internally in the HAL implementation, and can not be
+ * triggered from the test case
+ */
+TEST_P(WifiRttControllerHidlTest, RegisterEventCallback_1_6) {
+    sp<WifiRttControllerEventCallback> wifiRttControllerEventCallback =
+            new WifiRttControllerEventCallback();
+    const auto& status = HIDL_INVOKE(wifi_rtt_controller_, registerEventCallback_1_6,
+                                     wifiRttControllerEventCallback);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+}
+
+/*
+ * Request2SidedRangeMeasurement
+ * This test case tests the two sided ranging - 802.11mc FTM protocol.
+ */
+TEST_P(WifiRttControllerHidlTest, Request2SidedRangeMeasurement) {
+    std::pair<WifiStatus, RttCapabilities> status_and_caps;
+
+    // Get the Capabilities
+    status_and_caps = HIDL_INVOKE(wifi_rtt_controller_, getCapabilities_1_6);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
+    if (!status_and_caps.second.rttFtmSupported) {
+        GTEST_SKIP() << "Skipping two sided RTT since driver/fw doesn't support";
+    }
+    std::vector<RttConfig> configs;
+    RttConfig config;
+    int cmdId = 55;
+    // Set the config with test data
+    for (int i = 0; i < 6; i++) {
+        config.addr[i] = i;
+    }
+    config.type = RttType::TWO_SIDED;
+    config.peer = RttPeerType::AP;
+    config.channel.width = WifiChannelWidthInMhz::WIDTH_80;
+    config.channel.centerFreq = 5180;
+    config.channel.centerFreq0 = 5210;
+    config.channel.centerFreq1 = 0;
+    config.bw = RttBw::BW_20MHZ;
+    config.preamble = RttPreamble::HT;
+    config.mustRequestLci = false;
+    config.mustRequestLcr = false;
+    config.burstPeriod = 0;
+    config.numBurst = 0;
+    config.numFramesPerBurst = 8;
+    config.numRetriesPerRttFrame = 0;
+    config.numRetriesPerFtmr = 0;
+    config.burstDuration = 9;
+    // Insert config in the vector
+    configs.push_back(config);
+
+    // Invoke the call
+    const auto& status = HIDL_INVOKE(wifi_rtt_controller_, rangeRequest_1_6, cmdId, configs);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+    // sleep for 2 seconds to wait for driver/firmware to complete RTT
+    sleep(2);
+}
+
+/*
+ * rangeRequest_1_6
+ */
+TEST_P(WifiRttControllerHidlTest, RangeRequest_1_6) {
+    std::pair<WifiStatus, RttCapabilities> status_and_caps;
+
+    // Get the Capabilities
+    status_and_caps = HIDL_INVOKE(wifi_rtt_controller_, getCapabilities_1_6);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
+    if (!status_and_caps.second.rttOneSidedSupported) {
+        GTEST_SKIP() << "Skipping one sided RTT since driver/fw doesn't support";
+    }
+    // Get the highest support preamble
+    int preamble = 1;
+    status_and_caps.second.preambleSupport >>= 1;
+    while (status_and_caps.second.preambleSupport != 0) {
+        status_and_caps.second.preambleSupport >>= 1;
+        preamble <<= 1;
+    }
+    std::vector<RttConfig> configs;
+    RttConfig config;
+    int cmdId = 55;
+    // Set the config with test data
+    for (int i = 0; i < 6; i++) {
+        config.addr[i] = i;
+    }
+    config.type = RttType::ONE_SIDED;
+    config.peer = RttPeerType::AP;
+    config.channel.width = WifiChannelWidthInMhz::WIDTH_80;
+    config.channel.centerFreq = 5765;
+    config.channel.centerFreq0 = 5775;
+    config.channel.centerFreq1 = 0;
+    config.bw = RttBw::BW_80MHZ;
+    config.preamble = (RttPreamble)preamble;
+    config.mustRequestLci = false;
+    config.mustRequestLcr = false;
+    config.burstPeriod = 0;
+    config.numBurst = 0;
+    config.numFramesPerBurst = 8;
+    config.numRetriesPerRttFrame = 3;
+    config.numRetriesPerFtmr = 3;
+    config.burstDuration = 9;
+    // Insert config in the vector
+    configs.push_back(config);
+
+    // Invoke the call
+    const auto& status = HIDL_INVOKE(wifi_rtt_controller_, rangeRequest_1_6, cmdId, configs);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+    // sleep for 2 seconds to wait for driver/firmware to complete RTT
+    sleep(2);
+}
+
+/*
+ * getCapabilities_1_6
+ */
+TEST_P(WifiRttControllerHidlTest, GetCapabilities_1_6) {
+    std::pair<WifiStatus, RttCapabilities> status_and_caps;
+
+    // Invoke the call
+    status_and_caps = HIDL_INVOKE(wifi_rtt_controller_, getCapabilities_1_6);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
+}
+
+/*
+ * getResponderInfo_1_6
+ */
+TEST_P(WifiRttControllerHidlTest, GetResponderInfo_1_6) {
+    std::pair<WifiStatus, RttResponder> status_and_info;
+
+    // Invoke the call
+    status_and_info = HIDL_INVOKE(wifi_rtt_controller_, getResponderInfo_1_6);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_info.first.code);
+}
+
+/*
+ * enableResponder_1_6
+ */
+TEST_P(WifiRttControllerHidlTest, EnableResponder_1_6) {
+    std::pair<WifiStatus, RttResponder> status_and_info;
+    int cmdId = 55;
+    WifiChannelInfo channelInfo;
+    channelInfo.width = WifiChannelWidthInMhz::WIDTH_80;
+    channelInfo.centerFreq = 5660;
+    channelInfo.centerFreq0 = 5660;
+    channelInfo.centerFreq1 = 0;
+
+    // Get the responder first
+    status_and_info = HIDL_INVOKE(wifi_rtt_controller_, getResponderInfo_1_6);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_info.first.code);
+
+    // Invoke the call
+    const auto& status = HIDL_INVOKE(wifi_rtt_controller_, enableResponder_1_6, cmdId, channelInfo,
+                                     10, status_and_info.second);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiRttControllerHidlTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, WifiRttControllerHidlTest,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 ::android::hardware::wifi::V1_6::IWifi::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
diff --git a/wifi/1.6/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.6/vts/functional/wifi_sta_iface_hidl_test.cpp
new file mode 100644
index 0000000..4a6fd27
--- /dev/null
+++ b/wifi/1.6/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Staache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <numeric>
+#include <vector>
+
+#include <android-base/logging.h>
+
+#include <android/hardware/wifi/1.6/IWifi.h>
+#include <android/hardware/wifi/1.6/IWifiChip.h>
+#include <android/hardware/wifi/1.6/IWifiStaIface.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "wifi_hidl_call_util.h"
+#include "wifi_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_6::IWifiChip;
+using ::android::hardware::wifi::V1_6::IWifiStaIface;
+
+/**
+ * Fixture to use for all STA Iface HIDL interface tests.
+ */
+class WifiStaIfaceHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        // Make sure to start with a clean state
+        stopWifi(GetInstanceName());
+
+        wifi_sta_iface_ = IWifiStaIface::castFrom(getWifiStaIface(GetInstanceName()));
+        ASSERT_NE(nullptr, wifi_sta_iface_.get());
+    }
+
+    virtual void TearDown() override { stopWifi(GetInstanceName()); }
+
+  protected:
+    bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask cap_mask) {
+        const auto& status_and_caps = HIDL_INVOKE(wifi_sta_iface_, getCapabilities);
+        EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
+        return (status_and_caps.second & cap_mask) != 0;
+    }
+
+    WifiStatusCode createStaIface(sp<IWifiStaIface>* sta_iface) {
+        sp<IWifiChip> wifi_chip = IWifiChip::castFrom(getWifiChip(GetInstanceName()));
+        EXPECT_NE(nullptr, wifi_chip.get());
+        const auto& status_and_iface = HIDL_INVOKE(wifi_chip, createStaIface);
+        *sta_iface = IWifiStaIface::castFrom(status_and_iface.second);
+        return status_and_iface.first.code;
+    }
+
+    sp<IWifiStaIface> wifi_sta_iface_;
+
+  private:
+    std::string GetInstanceName() { return GetParam(); }
+};
+
+/*
+ * GetLinkLayerStats_1_6
+ * Ensures that calls to get link layer stats V1_6 will retrieve a non-empty
+ * StaLinkLayerStats after link layer stats collection is enabled.
+ */
+TEST_P(WifiStaIfaceHidlTest, GetLinkLayerStats_1_6) {
+    if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) {
+        GTEST_SKIP() << "Skipping this test since link layer stats are not supported.";
+    }
+
+    // Enable link layer stats collection.
+    EXPECT_EQ(WifiStatusCode::SUCCESS,
+              HIDL_INVOKE(wifi_sta_iface_, enableLinkLayerStatsCollection, true).code);
+    // Retrieve link layer stats.
+    const auto& status_and_stats = HIDL_INVOKE(wifi_sta_iface_, getLinkLayerStats_1_6);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_stats.first.code);
+    EXPECT_GT(status_and_stats.second.timeStampInMs, 0u);
+    // Try to create 2nd iface. If yes, it should fill in the duty cycle field.
+    sp<IWifiStaIface> iface;
+    auto status = createStaIface(&iface);
+    if (status == WifiStatusCode::SUCCESS) {
+        EXPECT_GT(status_and_stats.second.iface.timeSliceDutyCycleInPercent, 0u);
+    }
+    // Disable link layer stats collection.
+    EXPECT_EQ(WifiStatusCode::SUCCESS,
+              HIDL_INVOKE(wifi_sta_iface_, disableLinkLayerStatsCollection).code);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiStaIfaceHidlTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, WifiStaIfaceHidlTest,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 ::android::hardware::wifi::V1_6::IWifi::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
diff --git a/wifi/hostapd/1.3/vts/functional/Android.bp b/wifi/hostapd/1.3/vts/functional/Android.bp
index 6eceadf..78cd4af 100644
--- a/wifi/hostapd/1.3/vts/functional/Android.bp
+++ b/wifi/hostapd/1.3/vts/functional/Android.bp
@@ -26,6 +26,9 @@
 cc_test {
     name: "VtsHalWifiHostapdV1_3TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: [
+        "hostapd_hidl_test.cpp",
+    ],
     srcs: [
         "hostapd_hidl_test.cpp",
     ],
diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl
index af0e960..5bb0d32 100644
--- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl
+++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl
@@ -38,7 +38,7 @@
   WIFI_STANDARD_LEGACY = 0,
   WIFI_STANDARD_11N = 1,
   WIFI_STANDARD_11AC = 2,
-  WIFI_STANDARD_11AX = 3,
-  WIFI_STANDARD_11AD = 4,
+  WIFI_STANDARD_11AD = 3,
+  WIFI_STANDARD_11AX = 4,
   WIFI_STANDARD_11BE = 5,
 }
diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Generation.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Generation.aidl
index f4e3eb0..5b74732 100644
--- a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Generation.aidl
+++ b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/Generation.aidl
@@ -25,8 +25,8 @@
  * WIFI_STANDARD_11N = [hw_mode is HOSTAPD_MODE_IEEE80211G and (HT is 1 or HT40 is 1)] or
  *                     [hw_mode is HOSTAPD_MODE_IEEE80211A and VHT is 0].
  * WIFI_STANDARD_11AC = hw_mode is HOSTAPD_MODE_IEEE80211A and VHT is 1.
- * WIFI_STANDARD_11AX = hw_mode is HOSTAPD_MODE_IEEE80211A and High Efficiency supported.
  * WIFI_STANDARD_11AD = hw_mode is HOSTAPD_MODE_IEEE80211AD.
+ * WIFI_STANDARD_11AX = hw_mode is HOSTAPD_MODE_IEEE80211A and High Efficiency supported.
  * WIFI_STANDARD_11BE = hw_mode is HOSTAPD_MODE_IEEE80211A and Extreme High Throughput supported.
  */
 @VintfStability
@@ -36,7 +36,7 @@
     WIFI_STANDARD_LEGACY = 0,
     WIFI_STANDARD_11N = 1,
     WIFI_STANDARD_11AC = 2,
-    WIFI_STANDARD_11AX = 3,
-    WIFI_STANDARD_11AD = 4,
+    WIFI_STANDARD_11AD = 3,
+    WIFI_STANDARD_11AX = 4,
     WIFI_STANDARD_11BE = 5,
 }
diff --git a/wifi/netlinkinterceptor/libnlinterceptor/include/libnlinterceptor/libnlinterceptor.h b/wifi/netlinkinterceptor/libnlinterceptor/include/libnlinterceptor/libnlinterceptor.h
index ac8653e..32e5a6e 100644
--- a/wifi/netlinkinterceptor/libnlinterceptor/include/libnlinterceptor/libnlinterceptor.h
+++ b/wifi/netlinkinterceptor/libnlinterceptor/include/libnlinterceptor/libnlinterceptor.h
@@ -117,14 +117,13 @@
     int clientSocketFd, const char* clientName,
     struct android_nlinterceptor_InterceptedSocket* interceptedSocket);
 
-void android_nlinterceptor_closeSocket(
-    const struct android_nlinterceptor_InterceptedSocket* sock);
+void android_nlinterceptor_closeSocket(struct android_nlinterceptor_InterceptedSocket sock);
 
-bool android_nlinterceptor_subscribe(
-    const struct android_nlinterceptor_InterceptedSocket* sock, uint32_t group);
+bool android_nlinterceptor_subscribe(struct android_nlinterceptor_InterceptedSocket sock,
+                                     uint32_t group);
 
-bool android_nlinterceptor_unsubscribe(
-    const struct android_nlinterceptor_InterceptedSocket* sock, uint32_t group);
+bool android_nlinterceptor_unsubscribe(struct android_nlinterceptor_InterceptedSocket sock,
+                                       uint32_t group);
 
 #ifdef __cplusplus
 }
diff --git a/wifi/netlinkinterceptor/libnlinterceptor/libnlinterceptor.cpp b/wifi/netlinkinterceptor/libnlinterceptor/libnlinterceptor.cpp
index 575f900..aae7a3a 100644
--- a/wifi/netlinkinterceptor/libnlinterceptor/libnlinterceptor.cpp
+++ b/wifi/netlinkinterceptor/libnlinterceptor/libnlinterceptor.cpp
@@ -150,25 +150,18 @@
     return true;
 }
 
-extern "C" void android_nlinterceptor_closeSocket(
-    const android_nlinterceptor_InterceptedSocket* sock) {
-    if (!sock) {
-        LOG(ERROR) << "Can't close socket identified by a null pointer!";
-        return;
-    }
-    closeSocket({sock->nlFamily, sock->portId});
+extern "C" void android_nlinterceptor_closeSocket(android_nlinterceptor_InterceptedSocket sock) {
+    closeSocket({sock.nlFamily, sock.portId});
 }
 
-extern "C" bool android_nlinterceptor_subscribe(
-    const android_nlinterceptor_InterceptedSocket* sock, uint32_t group) {
-    if (!sock) return false;
-    return subscribe({sock->nlFamily, sock->portId}, group);
+extern "C" bool android_nlinterceptor_subscribe(android_nlinterceptor_InterceptedSocket sock,
+                                                uint32_t group) {
+    return subscribe({sock.nlFamily, sock.portId}, group);
 }
 
-extern "C" bool android_nlinterceptor_unsubscribe(
-    const android_nlinterceptor_InterceptedSocket* sock, uint32_t group) {
-    if (!sock) return false;
-    return unsubscribe({sock->nlFamily, sock->portId}, group);
+extern "C" bool android_nlinterceptor_unsubscribe(android_nlinterceptor_InterceptedSocket sock,
+                                                  uint32_t group) {
+    return unsubscribe({sock.nlFamily, sock.portId}, group);
 }
 
 }  // namespace android::nlinterceptor
diff --git a/wifi/netlinkinterceptor/vts/functional/Android.bp b/wifi/netlinkinterceptor/vts/functional/Android.bp
index 33284e8..80608a7 100644
--- a/wifi/netlinkinterceptor/vts/functional/Android.bp
+++ b/wifi/netlinkinterceptor/vts/functional/Android.bp
@@ -34,13 +34,13 @@
         "interceptor_aidl_test.cpp",
     ],
     shared_libs: [
-        "android.hardware.net.nlinterceptor-V1-ndk",
         "libbase",
         "libbinder_ndk",
     ],
     static_libs: [
-        "libgmock",
+        "android.hardware.net.nlinterceptor-V1-ndk",
         "android.hardware.automotive.can@libnetdevice",
+        "libgmock",
         "libnl++",
     ],
     test_suites: [
diff --git a/wifi/supplicant/1.0/vts/functional/Android.bp b/wifi/supplicant/1.0/vts/functional/Android.bp
index 121117c..2d86822 100644
--- a/wifi/supplicant/1.0/vts/functional/Android.bp
+++ b/wifi/supplicant/1.0/vts/functional/Android.bp
@@ -44,6 +44,9 @@
 cc_test {
     name: "VtsHalWifiSupplicantV1_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: [
+        "supplicant_sta_network_hidl_test.cpp",
+    ],
     srcs: [
         "supplicant_hidl_test.cpp",
         "supplicant_sta_iface_hidl_test.cpp",
@@ -71,6 +74,9 @@
 cc_test {
     name: "VtsHalWifiSupplicantP2pV1_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
+    tidy_timeout_srcs: [
+        "supplicant_p2p_iface_hidl_test.cpp",
+    ],
     srcs: [
         "VtsHalWifiSupplicantP2pV1_0TargetTest.cpp",
         "supplicant_p2p_iface_hidl_test.cpp",
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/BufferType.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AuxiliarySupplicantEventCode.aidl
similarity index 88%
rename from drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/BufferType.aidl
rename to wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AuxiliarySupplicantEventCode.aidl
index b6ec34d..471cfff 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/BufferType.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/AuxiliarySupplicantEventCode.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -31,9 +31,10 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.drm;
+package android.hardware.wifi.supplicant;
 @Backing(type="int") @VintfStability
-enum BufferType {
-  SHARED_MEMORY = 0,
-  NATIVE_HANDLE = 1,
+enum AuxiliarySupplicantEventCode {
+  EAP_METHOD_SELECTED = 0,
+  SSID_TEMP_DISABLED = 1,
+  OPEN_SSL_FAILURE = 2,
 }
diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppConnectionKeys.aidl
similarity index 89%
copy from drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl
copy to wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppConnectionKeys.aidl
index d2b48d2..559d1c9 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/DecryptResult.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppConnectionKeys.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -31,9 +31,10 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.drm;
+package android.hardware.wifi.supplicant;
 @VintfStability
-parcelable DecryptResult {
-  int bytesWritten;
-  String detailedError;
+parcelable DppConnectionKeys {
+  byte[] connector;
+  byte[] cSign;
+  byte[] netAccessKey;
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicant.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicant.aidl
index b4371fd..4b26ac3 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicant.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicant.aidl
@@ -34,11 +34,11 @@
 package android.hardware.wifi.supplicant;
 @VintfStability
 interface ISupplicant {
-  android.hardware.wifi.supplicant.ISupplicantP2pIface addP2pInterface(in String ifName);
-  android.hardware.wifi.supplicant.ISupplicantStaIface addStaInterface(in String ifName);
+  @PropagateAllowBlocking android.hardware.wifi.supplicant.ISupplicantP2pIface addP2pInterface(in String ifName);
+  @PropagateAllowBlocking android.hardware.wifi.supplicant.ISupplicantStaIface addStaInterface(in String ifName);
   android.hardware.wifi.supplicant.DebugLevel getDebugLevel();
-  android.hardware.wifi.supplicant.ISupplicantP2pIface getP2pInterface(in String ifName);
-  android.hardware.wifi.supplicant.ISupplicantStaIface getStaInterface(in String ifName);
+  @PropagateAllowBlocking android.hardware.wifi.supplicant.ISupplicantP2pIface getP2pInterface(in String ifName);
+  @PropagateAllowBlocking android.hardware.wifi.supplicant.ISupplicantStaIface getStaInterface(in String ifName);
   boolean isDebugShowKeysEnabled();
   boolean isDebugShowTimestampEnabled();
   android.hardware.wifi.supplicant.IfaceInfo[] listInterfaces();
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantCallback.aidl
index 72ab3b9..7281053 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantCallback.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantCallback.aidl
@@ -36,5 +36,4 @@
 interface ISupplicantCallback {
   oneway void onInterfaceCreated(in String ifaceName);
   oneway void onInterfaceRemoved(in String ifaceName);
-  oneway void onTerminating();
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
index d7eff76..e204184 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
@@ -37,7 +37,7 @@
   void addBonjourService(in byte[] query, in byte[] response);
   void addGroup(in boolean persistent, in int persistentNetworkId);
   void addGroupWithConfig(in byte[] ssid, in String pskPassphrase, in boolean persistent, in int freq, in byte[] peerAddress, in boolean joinExistingGroup);
-  android.hardware.wifi.supplicant.ISupplicantP2pNetwork addNetwork();
+  @PropagateAllowBlocking android.hardware.wifi.supplicant.ISupplicantP2pNetwork addNetwork();
   void addUpnpService(in int version, in String serviceName);
   void cancelConnect();
   void cancelServiceDiscovery(in long identifier);
@@ -54,7 +54,7 @@
   boolean getEdmg();
   android.hardware.wifi.supplicant.P2pGroupCapabilityMask getGroupCapability(in byte[] peerAddress);
   String getName();
-  android.hardware.wifi.supplicant.ISupplicantP2pNetwork getNetwork(in int id);
+  @PropagateAllowBlocking android.hardware.wifi.supplicant.ISupplicantP2pNetwork getNetwork(in int id);
   byte[] getSsid(in byte[] peerAddress);
   android.hardware.wifi.supplicant.IfaceType getType();
   void invite(in String groupIfName, in byte[] goDeviceAddress, in byte[] peerAddress);
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
index ed6e7c9..53d5770 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
@@ -36,7 +36,7 @@
 interface ISupplicantStaIface {
   int addDppPeerUri(in String uri);
   int addExtRadioWork(in String name, in int freqInMhz, in int timeoutInSec);
-  android.hardware.wifi.supplicant.ISupplicantStaNetwork addNetwork();
+  @PropagateAllowBlocking android.hardware.wifi.supplicant.ISupplicantStaNetwork addNetwork();
   void addRxFilter(in android.hardware.wifi.supplicant.RxFilterType type);
   void cancelWps();
   void disconnect();
@@ -44,12 +44,13 @@
   void filsHlpAddRequest(in byte[] dst_mac, in byte[] pkt);
   void filsHlpFlushRequest();
   android.hardware.wifi.supplicant.DppResponderBootstrapInfo generateDppBootstrapInfoForResponder(in byte[] macAddress, in String deviceInfo, in android.hardware.wifi.supplicant.DppCurve curve);
+  void generateSelfDppConfiguration(in String ssid, in byte[] privEcKey);
   android.hardware.wifi.supplicant.ConnectionCapabilities getConnectionCapabilities();
   android.hardware.wifi.supplicant.MloLinksInfo getConnectionMloLinksInfo();
   android.hardware.wifi.supplicant.KeyMgmtMask getKeyMgmtCapabilities();
   byte[] getMacAddress();
   String getName();
-  android.hardware.wifi.supplicant.ISupplicantStaNetwork getNetwork(in int id);
+  @PropagateAllowBlocking android.hardware.wifi.supplicant.ISupplicantStaNetwork getNetwork(in int id);
   android.hardware.wifi.supplicant.IfaceType getType();
   android.hardware.wifi.supplicant.WpaDriverCapabilitiesMask getWpaDriverCapabilities();
   void initiateAnqpQuery(in byte[] macAddress, in android.hardware.wifi.supplicant.AnqpInfoId[] infoElements, in android.hardware.wifi.supplicant.Hs20AnqpSubtypes[] subTypes);
@@ -63,7 +64,7 @@
   void reconnect();
   void registerCallback(in android.hardware.wifi.supplicant.ISupplicantStaIfaceCallback callback);
   void setQosPolicyFeatureEnabled(in boolean enable);
-  void sendQosPolicyResponse(in boolean morePolicies, in android.hardware.wifi.supplicant.QosPolicyStatus[] qosPolicyStatusList);
+  void sendQosPolicyResponse(in int qosPolicyRequestId, in boolean morePolicies, in android.hardware.wifi.supplicant.QosPolicyStatus[] qosPolicyStatusList);
   void removeAllQosPolicies();
   void removeDppUri(in int id);
   void removeExtRadioWork(in int id);
@@ -83,7 +84,7 @@
   void setWpsModelName(in String modelName);
   void setWpsModelNumber(in String modelNumber);
   void setWpsSerialNumber(in String serialNumber);
-  void startDppConfiguratorInitiator(in int peerBootstrapId, in int ownBootstrapId, in String ssid, in String password, in String psk, in android.hardware.wifi.supplicant.DppNetRole netRole, in android.hardware.wifi.supplicant.DppAkm securityAkm);
+  byte[] startDppConfiguratorInitiator(in int peerBootstrapId, in int ownBootstrapId, in String ssid, in String password, in String psk, in android.hardware.wifi.supplicant.DppNetRole netRole, in android.hardware.wifi.supplicant.DppAkm securityAkm, in byte[] privEcKey);
   void startDppEnrolleeInitiator(in int peerBootstrapId, in int ownBootstrapId);
   void startDppEnrolleeResponder(in int listenChannel);
   void startRxFilter();
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
index c17c624..25a09b4 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -37,15 +37,16 @@
   oneway void onAnqpQueryDone(in byte[] bssid, in android.hardware.wifi.supplicant.AnqpData data, in android.hardware.wifi.supplicant.Hs20AnqpData hs20Data);
   oneway void onAssociationRejected(in android.hardware.wifi.supplicant.AssociationRejectionData assocRejectData);
   oneway void onAuthenticationTimeout(in byte[] bssid);
+  oneway void onAuxiliarySupplicantEvent(in android.hardware.wifi.supplicant.AuxiliarySupplicantEventCode eventCode, in byte[] bssid, in String reasonString);
   oneway void onBssTmHandlingDone(in android.hardware.wifi.supplicant.BssTmData tmData);
   oneway void onBssidChanged(in android.hardware.wifi.supplicant.BssidChangeReason reason, in byte[] bssid);
   oneway void onDisconnected(in byte[] bssid, in boolean locallyGenerated, in android.hardware.wifi.supplicant.StaIfaceReasonCode reasonCode);
   oneway void onDppFailure(in android.hardware.wifi.supplicant.DppFailureCode code, in String ssid, in String channelList, in char[] bandList);
   oneway void onDppProgress(in android.hardware.wifi.supplicant.DppProgressCode code);
   oneway void onDppSuccess(in android.hardware.wifi.supplicant.DppEventType event);
-  oneway void onDppSuccessConfigReceived(in byte[] ssid, in String password, in byte[] psk, in android.hardware.wifi.supplicant.DppAkm securityAkm);
+  oneway void onDppSuccessConfigReceived(in byte[] ssid, in String password, in byte[] psk, in android.hardware.wifi.supplicant.DppAkm securityAkm, in android.hardware.wifi.supplicant.DppConnectionKeys dppConnectionKeys);
   oneway void onDppSuccessConfigSent();
-  oneway void onEapFailure(in int errorCode);
+  oneway void onEapFailure(in byte[] bssid, in int errorCode);
   oneway void onExtRadioWorkStart(in int id);
   oneway void onExtRadioWorkTimeout(in int id);
   oneway void onHs20DeauthImminentNotice(in byte[] bssid, in int reasonCode, in int reAuthDelayInSec, in String url);
@@ -61,5 +62,5 @@
   oneway void onWpsEventPbcOverlap();
   oneway void onWpsEventSuccess();
   oneway void onQosPolicyReset();
-  oneway void onQosPolicyRequest(in android.hardware.wifi.supplicant.QosPolicyData[] qosPolicyData);
+  oneway void onQosPolicyRequest(in int qosPolicyRequestId, in android.hardware.wifi.supplicant.QosPolicyData[] qosPolicyData);
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
index bdc5f34..0b3cb81 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
@@ -87,6 +87,7 @@
   void sendNetworkEapSimUmtsAutsResponse(in byte[] auts);
   void setAuthAlg(in android.hardware.wifi.supplicant.AuthAlgMask authAlgMask);
   void setBssid(in byte[] bssid);
+  void setDppKeys(in android.hardware.wifi.supplicant.DppConnectionKeys keys);
   void setEapAltSubjectMatch(in String match);
   void setEapAnonymousIdentity(in byte[] identity);
   void setEapCACert(in String path);
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/AuxiliarySupplicantEventCode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/AuxiliarySupplicantEventCode.aidl
new file mode 100644
index 0000000..c0035c4
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/AuxiliarySupplicantEventCode.aidl
@@ -0,0 +1,31 @@
+/*
+ * 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.wifi.supplicant;
+
+/**
+ * Event codes for auxiliary events that can be generated by
+ * the supplicant. This includes events that are not major
+ * state changes (e.g. Connected, Disconnected), but that the
+ * client may still want to be alerted about.
+ */
+@VintfStability
+@Backing(type="int")
+enum AuxiliarySupplicantEventCode {
+    EAP_METHOD_SELECTED,
+    SSID_TEMP_DISABLED,
+    OPEN_SSL_FAILURE
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppConnectionKeys.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppConnectionKeys.aidl
new file mode 100644
index 0000000..056756b
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppConnectionKeys.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * connection keys that are used for DPP network connection.
+ */
+@VintfStability
+parcelable DppConnectionKeys {
+    /**
+     * DPP Connector (signedConnector)
+     */
+    byte[] connector;
+    /**
+     * C-sign-key (Configurator public key)
+     */
+    byte[] cSign;
+    /**
+     * DPP net access key (own private key)
+     */
+    byte[] netAccessKey;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicant.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicant.aidl
index 2ac1db7..c17289d 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicant.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicant.aidl
@@ -46,8 +46,8 @@
      *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
      *         |SupplicantStatusCode.FAILURE_IFACE_EXISTS|
      */
-    ISupplicantP2pIface addP2pInterface(in String ifName);
-    ISupplicantStaIface addStaInterface(in String ifName);
+    @PropagateAllowBlocking ISupplicantP2pIface addP2pInterface(in String ifName);
+    @PropagateAllowBlocking ISupplicantStaIface addStaInterface(in String ifName);
 
     /**
      * Get the debug level set.
@@ -68,8 +68,8 @@
      *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
      *         |SupplicantStatusCode.FAILURE_IFACE_UNKNOWN|
      */
-    ISupplicantP2pIface getP2pInterface(in String ifName);
-    ISupplicantStaIface getStaInterface(in String ifName);
+    @PropagateAllowBlocking ISupplicantP2pIface getP2pInterface(in String ifName);
+    @PropagateAllowBlocking ISupplicantStaIface getStaInterface(in String ifName);
 
     /**
      * Get whether the keys are shown in the debug logs or not.
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantCallback.aidl
index 6f15900..8e59ec9 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantCallback.aidl
@@ -24,23 +24,18 @@
  * |ISupplicant.registerCallback| method.
  */
 @VintfStability
-interface ISupplicantCallback {
+oneway interface ISupplicantCallback {
     /**
      * Used to indicate that a new interface has been created.
      *
      * @param ifaceName Name of the network interface, e.g., wlan0
      */
-    oneway void onInterfaceCreated(in String ifaceName);
+    void onInterfaceCreated(in String ifaceName);
 
     /**
      * Used to indicate that an interface has been removed.
      *
      * @param ifaceName Name of the network interface, e.g., wlan0
      */
-    oneway void onInterfaceRemoved(in String ifaceName);
-
-    /**
-     * Used to indicate that the supplicant daemon is terminating.
-     */
-    oneway void onTerminating();
+    void onInterfaceRemoved(in String ifaceName);
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
index 9021bf5..313ee8b 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIface.aidl
@@ -104,7 +104,7 @@
      *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
      *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
      */
-    ISupplicantP2pNetwork addNetwork();
+    @PropagateAllowBlocking ISupplicantP2pNetwork addNetwork();
 
     /**
      * This command can be used to add a UPNP service.
@@ -321,7 +321,7 @@
      *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
      *         |SupplicantStatusCode.FAILURE_NETWORK_UNKNOWN|
      */
-    ISupplicantP2pNetwork getNetwork(in int id);
+    @PropagateAllowBlocking ISupplicantP2pNetwork getNetwork(in int id);
 
     /**
      * Gets the operational SSID of the device.
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
index da17c7b..7c8c1f2 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
@@ -31,7 +31,7 @@
  * corresponding |ISupplicantP2pIface.registerCallback| method.
  */
 @VintfStability
-interface ISupplicantP2pIfaceCallback {
+oneway interface ISupplicantP2pIfaceCallback {
     /**
      * Used to indicate that a P2P device has been found.
      *
@@ -50,7 +50,7 @@
      * @param wfdDeviceInfo WFD device info as described in section 5.1.2 of WFD
      *        technical specification v1.0.0.
      */
-    oneway void onDeviceFound(in byte[] srcAddress, in byte[] p2pDeviceAddress,
+    void onDeviceFound(in byte[] srcAddress, in byte[] p2pDeviceAddress,
             in byte[] primaryDeviceType, in String deviceName, in WpsConfigMethods configMethods,
             in byte deviceCapabilities, in P2pGroupCapabilityMask groupCapabilities,
             in byte[] wfdDeviceInfo);
@@ -60,19 +60,19 @@
      *
      * @param p2pDeviceAddress P2P device address.
      */
-    oneway void onDeviceLost(in byte[] p2pDeviceAddress);
+    void onDeviceLost(in byte[] p2pDeviceAddress);
 
     /**
      * Used to indicate the termination of P2P find operation.
      */
-    oneway void onFindStopped();
+    void onFindStopped();
 
     /**
      * Used to indicate the completion of a P2P Group Owner negotiation request.
      *
      * @param status Status of the GO negotiation.
      */
-    oneway void onGoNegotiationCompleted(in P2pStatusCode status);
+    void onGoNegotiationCompleted(in P2pStatusCode status);
 
     /**
      * Used to indicate the reception of a P2P Group Owner negotiation request.
@@ -81,19 +81,19 @@
      *        negotiation request.
      * @param passwordId Type of password.
      */
-    oneway void onGoNegotiationRequest(in byte[] srcAddress, in WpsDevPasswordId passwordId);
+    void onGoNegotiationRequest(in byte[] srcAddress, in WpsDevPasswordId passwordId);
 
     /**
      * Used to indicate a failure to form a P2P group.
      *
      * @param failureReason Failure reason string for debug purposes.
      */
-    oneway void onGroupFormationFailure(in String failureReason);
+    void onGroupFormationFailure(in String failureReason);
 
     /**
      * Used to indicate a successful formation of a P2P group.
      */
-    oneway void onGroupFormationSuccess();
+    void onGroupFormationSuccess();
 
     /**
      * Used to indicate the removal of a P2P group.
@@ -101,7 +101,7 @@
      * @param groupIfName Interface name of the group. (For ex: p2p-p2p0-1)
      * @param isGroupOwner Whether this device is owner of the group.
      */
-    oneway void onGroupRemoved(in String groupIfname, in boolean isGroupOwner);
+    void onGroupRemoved(in String groupIfname, in boolean isGroupOwner);
 
     /**
      * Used to indicate the start of a P2P group.
@@ -115,7 +115,7 @@
      * @param goDeviceAddress MAC Address of the owner of this group.
      * @param isPersistent Whether this group is persisted or not.
      */
-    oneway void onGroupStarted(in String groupIfname, in boolean isGroupOwner, in byte[] ssid,
+    void onGroupStarted(in String groupIfname, in boolean isGroupOwner, in byte[] ssid,
             in int frequency, in byte[] psk, in String passphrase, in byte[] goDeviceAddress,
             in boolean isPersistent);
 
@@ -128,8 +128,8 @@
      * @param persistentNetworkId Persistent network Id of the group.
      * @param operatingFrequency Frequency on which the invitation was received.
      */
-    oneway void onInvitationReceived(in byte[] srcAddress, in byte[] goDeviceAddress,
-            in byte[] bssid, in int persistentNetworkId, in int operatingFrequency);
+    void onInvitationReceived(in byte[] srcAddress, in byte[] goDeviceAddress, in byte[] bssid,
+            in int persistentNetworkId, in int operatingFrequency);
 
     /**
      * Used to indicate the result of the P2P invitation request.
@@ -137,7 +137,7 @@
      * @param bssid Bssid of the group.
      * @param status Status of the invitation.
      */
-    oneway void onInvitationResult(in byte[] bssid, in P2pStatusCode status);
+    void onInvitationResult(in byte[] bssid, in P2pStatusCode status);
 
     /**
      * Used to indicate the completion of a P2P provision discovery request.
@@ -148,7 +148,7 @@
      * @param configMethods Mask of WPS configuration methods supported.
      * @param generatedPin 8 digit pin generated.
      */
-    oneway void onProvisionDiscoveryCompleted(in byte[] p2pDeviceAddress, in boolean isRequest,
+    void onProvisionDiscoveryCompleted(in byte[] p2pDeviceAddress, in boolean isRequest,
             in P2pProvDiscStatusCode status, in WpsConfigMethods configMethods,
             in String generatedPin);
 
@@ -174,7 +174,7 @@
      * @param wfdR2DeviceInfo WFD R2 device info as described in section 5.1.12 of WFD
      *        technical specification v2.1.
      */
-    oneway void onR2DeviceFound(in byte[] srcAddress, in byte[] p2pDeviceAddress,
+    void onR2DeviceFound(in byte[] srcAddress, in byte[] p2pDeviceAddress,
             in byte[] primaryDeviceType, in String deviceName, in WpsConfigMethods configMethods,
             in byte deviceCapabilities, in P2pGroupCapabilityMask groupCapabilities,
             in byte[] wfdDeviceInfo, in byte[] wfdR2DeviceInfo);
@@ -187,8 +187,7 @@
      *        Wifi P2P Technical specification v1.2.
      * @parm tlvs Refer to section 3.1.3.1 of Wifi P2P Technical specification v1.2.
      */
-    oneway void onServiceDiscoveryResponse(
-            in byte[] srcAddress, in char updateIndicator, in byte[] tlvs);
+    void onServiceDiscoveryResponse(in byte[] srcAddress, in char updateIndicator, in byte[] tlvs);
 
     /**
      * Used to indicate when a STA device is connected to this device.
@@ -196,7 +195,7 @@
      * @param srcAddress MAC address of the device that was authorized.
      * @param p2pDeviceAddress P2P device address.
      */
-    oneway void onStaAuthorized(in byte[] srcAddress, in byte[] p2pDeviceAddress);
+    void onStaAuthorized(in byte[] srcAddress, in byte[] p2pDeviceAddress);
 
     /**
      * Used to indicate when a STA device is disconnected from this device.
@@ -204,7 +203,7 @@
      * @param srcAddress MAC address of the device that was deauthorized.
      * @param p2pDeviceAddress P2P device address.
      */
-    oneway void onStaDeauthorized(in byte[] srcAddress, in byte[] p2pDeviceAddress);
+    void onStaDeauthorized(in byte[] srcAddress, in byte[] p2pDeviceAddress);
 
     /**
      * Used to indicate that operating frequency has changed for this P2P group interface.
@@ -212,7 +211,7 @@
      * @param groupIfName Interface name of the group. (For ex: p2p-p2p0-1)
      * @param frequency New operating frequency in MHz.
      */
-    oneway void onGroupFrequencyChanged(in String groupIfname, in int frequency);
+    void onGroupFrequencyChanged(in String groupIfname, in int frequency);
 
     /**
      * Used to indicate that a P2P device has been found.
@@ -240,7 +239,7 @@
      *         Information technology. The length indicates the size of the payload.
      *         Multiple information elements may be appended within the byte array.
      */
-    oneway void onDeviceFoundWithVendorElements(in byte[] srcAddress, in byte[] p2pDeviceAddress,
+    void onDeviceFoundWithVendorElements(in byte[] srcAddress, in byte[] p2pDeviceAddress,
             in byte[] primaryDeviceType, in String deviceName, in WpsConfigMethods configMethods,
             in byte deviceCapabilities, in P2pGroupCapabilityMask groupCapabilities,
             in byte[] wfdDeviceInfo, in byte[] wfdR2DeviceInfo, in byte[] vendorElemBytes);
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
index 95e087f..9edf210 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
@@ -88,7 +88,7 @@
      *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
      *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
      */
-    ISupplicantStaNetwork addNetwork();
+    @PropagateAllowBlocking ISupplicantStaNetwork addNetwork();
 
     /**
      * Send driver command to add the specified RX filter.
@@ -180,6 +180,24 @@
             in byte[] macAddress, in String deviceInfo, in DppCurve curve);
 
     /**
+     * To Onboard / Configure self with DPP credentials.
+     *
+     * This is used to generate DppConnectionKeys for self. Thus a configurator
+     * can use the credentials to connect to an AP which it has configured for
+     * DPP AKM. This should be called before initiating first DPP connection
+     * on Configurator side. This API generates onDppSuccessConfigReceived()
+     * callback event asynchronously with DppConnectionKeys.
+     *
+     * @param ssid Network SSID configured profile
+     * @param privEcKey Private EC keys for this profile which was used to
+     *        configure other enrollee in network.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     *         |SupplicantStatusCode.FAILURE_UNSUPPORTED|
+     */
+    void generateSelfDppConfiguration(in String ssid, in byte[] privEcKey);
+
+    /**
      * Get Connection capabilities
      *
      * @return Connection capabilities.
@@ -242,7 +260,7 @@
      *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
      *         |SupplicantStatusCode.FAILURE_NETWORK_UNKNOWN|
      */
-    ISupplicantStaNetwork getNetwork(in int id);
+    @PropagateAllowBlocking ISupplicantStaNetwork getNetwork(in int id);
 
     /**
      * Retrieves the type of the network interface.
@@ -400,6 +418,7 @@
      * sends a solicited (uses the ongoing DSCP request as dialog token) DSCP
      * response. Otherwise, sends an unsolicited DSCP response.
      *
+     * @param qosPolicyRequestId Dialog token to identify the request.
      * @param morePolicies Flag to indicate more QoS policies can be accommodated.
      * @param qosPolicyStatusList QoS policy status info for each QoS policy id.
      * @throws ServiceSpecificException with one of the following values:
@@ -407,7 +426,8 @@
      *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
      *         |SupplicantStatusCode.FAILURE_UNSUPPORTED|
      */
-    void sendQosPolicyResponse(in boolean morePolicies, in QosPolicyStatus[] qosPolicyStatusList);
+    void sendQosPolicyResponse(in int qosPolicyRequestId, in boolean morePolicies,
+            in QosPolicyStatus[] qosPolicyStatusList);
 
     /**
      * Indicate removal of all active QoS policies configured by the AP.
@@ -434,12 +454,12 @@
      * This allows other radio works to be performed. If this method is not
      * invoked (e.g., due to the external program terminating), supplicant
      * must time out the radio work item on the iface and send
-     * |ISupplicantCallback.onExtRadioWorkTimeout| event to indicate
+     * |ISupplicantStaIfaceCallback.onExtRadioWorkTimeout| event to indicate
      * that this has happened.
      *
      * This method may also be used to cancel items that have been scheduled
      * via |addExtRadioWork|, but have not yet been started (notified via
-     * |ISupplicantCallback.onExtRadioWorkStart|).
+     * |ISupplicantStaIfaceCallback.onExtRadioWorkStart|).
      *
      * @param id Identifier generated for the radio work addition
      *         (using |addExtRadioWork|).
@@ -630,20 +650,27 @@
      *
      * @param peerBootstrapId Peer device's URI ID.
      * @param ownBootstrapId Local device's URI ID (0 for none, optional).
-     * @param ssid Network SSID to send to peer (SAE/PSK mode).
+     * @param ssid Network SSID to send to peer (SAE/PSK/DPP mode).
      * @param password Network password to send to peer (SAE/PSK mode).
      * @param psk Network PSK to send to peer (PSK mode only). Either password or psk should be set.
      * @param netRole Role to configure the peer, |DppNetRole.DPP_NET_ROLE_STA| or
      *        |DppNetRole.DPP_NET_ROLE_AP|.
      * @param securityAkm Security AKM to use (See DppAkm).
+     * @param privEcKey Private EC keys for this profile which was used to
+     *        configure other enrollee in network. This param is valid only for DPP AKM.
+     *        This param is set to Null by configurator to indicate first DPP-AKM based
+     *        configuration to an Enrollee. non-Null value indicates configurator had
+     *        previously configured an enrollee.
+     * @return Return the Private EC key when securityAkm is DPP and privEcKey was Null.
+     *         Otherwise return Null.
      * @throws ServiceSpecificException with one of the following values:
      *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
      *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
      *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
      */
-    void startDppConfiguratorInitiator(in int peerBootstrapId, in int ownBootstrapId,
+    byte[] startDppConfiguratorInitiator(in int peerBootstrapId, in int ownBootstrapId,
             in String ssid, in String password, in String psk, in DppNetRole netRole,
-            in DppAkm securityAkm);
+            in DppAkm securityAkm, in byte[] privEcKey);
 
     /**
      * Start DPP in Enrollee-Initiator mode.
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
index ca63f5c..0730a8c 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -18,9 +18,11 @@
 
 import android.hardware.wifi.supplicant.AnqpData;
 import android.hardware.wifi.supplicant.AssociationRejectionData;
+import android.hardware.wifi.supplicant.AuxiliarySupplicantEventCode;
 import android.hardware.wifi.supplicant.BssTmData;
 import android.hardware.wifi.supplicant.BssidChangeReason;
 import android.hardware.wifi.supplicant.DppAkm;
+import android.hardware.wifi.supplicant.DppConnectionKeys;
 import android.hardware.wifi.supplicant.DppEventType;
 import android.hardware.wifi.supplicant.DppFailureCode;
 import android.hardware.wifi.supplicant.DppProgressCode;
@@ -41,7 +43,7 @@
  * corresponding |ISupplicantStaIface.registerCallback| method.
  */
 @VintfStability
-interface ISupplicantStaIfaceCallback {
+oneway interface ISupplicantStaIfaceCallback {
     /**
      * Used to indicate the result of ANQP (either for IEEE 802.11u Interworking
      * or Hotspot 2.0) query.
@@ -52,7 +54,7 @@
      * @param hs20Data ANQP data fetched from the Hotspot 2.0 access point.
      *        All the fields in this struct must be empty if the query failed.
      */
-    oneway void onAnqpQueryDone(in byte[] bssid, in AnqpData data, in Hs20AnqpData hs20Data);
+    void onAnqpQueryDone(in byte[] bssid, in AnqpData data, in Hs20AnqpData hs20Data);
 
     /**
      * Used to indicate an association rejection received from the AP
@@ -60,14 +62,24 @@
      *
      * @param assocRejectData Association Rejection related information.
      */
-    oneway void onAssociationRejected(in AssociationRejectionData assocRejectData);
+    void onAssociationRejected(in AssociationRejectionData assocRejectData);
 
     /**
      * Used to indicate the timeout of authentication to an AP.
      *
      * @param bssid BSSID of the corresponding AP.
      */
-    oneway void onAuthenticationTimeout(in byte[] bssid);
+    void onAuthenticationTimeout(in byte[] bssid);
+
+    /**
+     * Indicates that an auxiliary event was generated by the supplicant.
+     *
+     * @param eventCode |AuxiliarySupplicantEventCode| for the event that occurred.
+     * @param bssid BSSID of the AP which caused the event.
+     * @param reasonString Additional information about why the event occurred.
+     */
+    void onAuxiliarySupplicantEvent(
+            in AuxiliarySupplicantEventCode eventCode, in byte[] bssid, in String reasonString);
 
     /**
      * Indicates BTM request frame handling status.
@@ -75,7 +87,7 @@
      * @param tmData Data retrieved from received BSS transition management
      * request frame.
      */
-    oneway void onBssTmHandlingDone(in BssTmData tmData);
+    void onBssTmHandlingDone(in BssTmData tmData);
 
     /**
      * Used to indicate the change of active bssid.
@@ -85,7 +97,7 @@
      * @param reason Reason why the bssid changed.
      * @param bssid BSSID of the corresponding AP.
      */
-    oneway void onBssidChanged(in BssidChangeReason reason, in byte[] bssid);
+    void onBssidChanged(in BssidChangeReason reason, in byte[] bssid);
 
     /**
      * Used to indicate the disconnection from the currently connected
@@ -97,7 +109,7 @@
      * @param reasonCode 802.11 code to indicate the disconnect reason
      *        from access point. Refer to section 8.4.1.7 of IEEE802.11 spec.
      */
-    oneway void onDisconnected(
+    void onDisconnected(
             in byte[] bssid, in boolean locallyGenerated, in StaIfaceReasonCode reasonCode);
 
     /**
@@ -114,51 +126,54 @@
      * bandList: A list of band parameters that are supported by the Enrollee expressed as the
      *     Operating Class.
      */
-    oneway void onDppFailure(
+    void onDppFailure(
             in DppFailureCode code, in String ssid, in String channelList, in char[] bandList);
 
     /**
      * Indicates a DPP progress event.
      */
-    oneway void onDppProgress(in DppProgressCode code);
+    void onDppProgress(in DppProgressCode code);
 
     /**
      * Indicates a DPP success event.
      */
-    oneway void onDppSuccess(in DppEventType event);
+    void onDppSuccess(in DppEventType event);
 
     /**
-     * Indicates DPP configuration received success event (Enrolee mode).
+     * Indicates DPP configuration received success event in Enrolee mode.
+     * This is also triggered when Configurator generates credentials for itself
+     * using generateSelfDppConfiguration() API
      */
-    oneway void onDppSuccessConfigReceived(
-            in byte[] ssid, in String password, in byte[] psk, in DppAkm securityAkm);
+    void onDppSuccessConfigReceived(in byte[] ssid, in String password, in byte[] psk,
+            in DppAkm securityAkm, in DppConnectionKeys dppConnectionKeys);
 
     /**
      * Indicates DPP configuration sent success event (Configurator mode).
      */
-    oneway void onDppSuccessConfigSent();
+    void onDppSuccessConfigSent();
 
     /**
      * Indicates an EAP authentication failure.
+     * @param bssid BSSID of the access point.
      * @param errorCode Error code for EAP authentication failure.
      *        Either standard error code (enum EapErrorCode) or
      *        private error code defined by network provider.
      */
-    oneway void onEapFailure(in int errorCode);
+    void onEapFailure(in byte[] bssid, in int errorCode);
 
     /**
      * Used to indicate that the external radio work can start now.
      *
      * @param id Identifier generated for the radio work request.
      */
-    oneway void onExtRadioWorkStart(in int id);
+    void onExtRadioWorkStart(in int id);
 
     /**
      * Used to indicate that the external radio work request has timed out.
      *
      * @param id Identifier generated for the radio work request.
      */
-    oneway void onExtRadioWorkTimeout(in int id);
+    void onExtRadioWorkTimeout(in int id);
 
     /**
      * Used to indicate a Hotspot 2.0 imminent deauth notice.
@@ -169,7 +184,7 @@
      * @param reAuthDelayInSec Delay before reauthenticating.
      * @param url URL of the server.
      */
-    oneway void onHs20DeauthImminentNotice(
+    void onHs20DeauthImminentNotice(
             in byte[] bssid, in int reasonCode, in int reAuthDelayInSec, in String url);
 
     /**
@@ -180,7 +195,7 @@
      * @param data Icon data fetched from the access point.
      *        Must be empty if the query failed.
      */
-    oneway void onHs20IconQueryDone(in byte[] bssid, in String fileName, in byte[] data);
+    void onHs20IconQueryDone(in byte[] bssid, in String fileName, in byte[] data);
 
     /**
      * Used to indicate a Hotspot 2.0 subscription remediation event.
@@ -189,8 +204,7 @@
      * @param osuMethod OSU method.
      * @param url URL of the server.
      */
-    oneway void onHs20SubscriptionRemediation(
-            in byte[] bssid, in OsuMethod osuMethod, in String url);
+    void onHs20SubscriptionRemediation(in byte[] bssid, in OsuMethod osuMethod, in String url);
 
     /**
      * Used to indicate a Hotspot 2.0 terms and conditions acceptance is requested from the user
@@ -199,15 +213,14 @@
      * @param bssid BSSID of the access point.
      * @param url URL of the T&C server.
      */
-    oneway void onHs20TermsAndConditionsAcceptanceRequestedNotification(
-            in byte[] bssid, in String url);
+    void onHs20TermsAndConditionsAcceptanceRequestedNotification(in byte[] bssid, in String url);
 
     /**
      * Used to indicate that a new network has been added.
      *
      * @param id Network ID allocated to the corresponding network.
      */
-    oneway void onNetworkAdded(in int id);
+    void onNetworkAdded(in int id);
 
     /**
      * Used to indicate that the supplicant failed to find a network in scan result
@@ -216,14 +229,14 @@
      *
      * @param ssid network name supplicant tried to connect.
      */
-    oneway void onNetworkNotFound(in byte[] ssid);
+    void onNetworkNotFound(in byte[] ssid);
 
     /**
      * Used to indicate that a network has been removed.
      *
      * @param id Network ID allocated to the corresponding network.
      */
-    oneway void onNetworkRemoved(in int id);
+    void onNetworkRemoved(in int id);
 
     /**
      * Indicates pairwise master key (PMK) cache added event.
@@ -232,7 +245,7 @@
      * @param serializedEntry is serialized PMK cache entry, the content is
      *              opaque for the framework and depends on the native implementation.
      */
-    oneway void onPmkCacheAdded(in long expirationTimeInSec, in byte[] serializedEntry);
+    void onPmkCacheAdded(in long expirationTimeInSec, in byte[] serializedEntry);
 
     /**
      * Used to indicate a state change event on this particular iface. If this
@@ -253,7 +266,7 @@
      *        to a particular network.
      * @param filsHlpSent If FILS HLP IEs were included in this association.
      */
-    oneway void onStateChanged(in StaIfaceCallbackState newState, in byte[] bssid, in int id,
+    void onStateChanged(in StaIfaceCallbackState newState, in byte[] bssid, in int id,
             in byte[] ssid, in boolean filsHlpSent);
 
     /**
@@ -264,29 +277,30 @@
      * @param configError Configuration error code.
      * @param errorInd Error indication code.
      */
-    oneway void onWpsEventFail(
+    void onWpsEventFail(
             in byte[] bssid, in WpsConfigError configError, in WpsErrorIndication errorInd);
 
     /**
      * Used to indicate the overlap of a WPS PBC connection attempt.
      */
-    oneway void onWpsEventPbcOverlap();
+    void onWpsEventPbcOverlap();
 
     /**
      * Used to indicate the success of a WPS connection attempt.
      */
-    oneway void onWpsEventSuccess();
+    void onWpsEventSuccess();
 
     /**
      * Used to indicate that the AP has cleared all DSCP requests
      * associated with this device.
      */
-    oneway void onQosPolicyReset();
+    void onQosPolicyReset();
 
     /**
      * Used to indicate a DSCP request was received from the AP.
      *
+     * @param qosPolicyRequestId Dialog token to identify the request.
      * @param qosPolicyData QoS policies info requested by the AP.
      */
-    oneway void onQosPolicyRequest(in QosPolicyData[] qosPolicyData);
+    void onQosPolicyRequest(in int qosPolicyRequestId, in QosPolicyData[] qosPolicyData);
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
index 1a2087d..267f1e8 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
@@ -17,6 +17,7 @@
 package android.hardware.wifi.supplicant;
 
 import android.hardware.wifi.supplicant.AuthAlgMask;
+import android.hardware.wifi.supplicant.DppConnectionKeys;
 import android.hardware.wifi.supplicant.EapMethod;
 import android.hardware.wifi.supplicant.EapPhase2Method;
 import android.hardware.wifi.supplicant.GroupCipherMask;
@@ -639,6 +640,18 @@
     void setBssid(in byte[] bssid);
 
     /**
+     * Set DPP keys for network which supports DPP AKM.
+     *
+     * @param keys connection keys needed to make DPP
+     * AKM based network connection.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setDppKeys(in DppConnectionKeys keys);
+
+    /**
      * Set EAP Alt subject match for this network.
      *
      * @param match value to set.
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
index 4024c35..de7b675 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
@@ -29,14 +29,14 @@
  * corresponding |ISupplicantStaNetwork.registerCallback| method.
  */
 @VintfStability
-interface ISupplicantStaNetworkCallback {
+oneway interface ISupplicantStaNetworkCallback {
     /**
      * Used to request EAP Identity for this particular network.
      *
      * The response for the request must be sent using the corresponding
      * |ISupplicantNetwork.sendNetworkEapIdentityResponse| call.
      */
-    oneway void onNetworkEapIdentityRequest();
+    void onNetworkEapIdentityRequest();
 
     /**
      * Used to request EAP GSM SIM authentication for this particular network.
@@ -46,7 +46,7 @@
      *
      * @param params Params associated with the request.
      */
-    oneway void onNetworkEapSimGsmAuthRequest(in NetworkRequestEapSimGsmAuthParams params);
+    void onNetworkEapSimGsmAuthRequest(in NetworkRequestEapSimGsmAuthParams params);
 
     /**
      * Used to request EAP UMTS SIM authentication for this particular network.
@@ -56,12 +56,12 @@
      *
      * @param params Params associated with the request.
      */
-    oneway void onNetworkEapSimUmtsAuthRequest(in NetworkRequestEapSimUmtsAuthParams params);
+    void onNetworkEapSimUmtsAuthRequest(in NetworkRequestEapSimUmtsAuthParams params);
 
     /**
      * Used to notify WPA3 transition disable.
      */
-    oneway void onTransitionDisable(in TransitionDisableIndication ind);
+    void onTransitionDisable(in TransitionDisableIndication ind);
 
     /**
      * Used to notify EAP certificate event.
@@ -69,6 +69,6 @@
      * On receiving a server certifidate from TLS handshake, send this certificate
      * to the framework for Trust On First Use.
      */
-    oneway void onServerCertificateAvailable(
+    void onServerCertificateAvailable(
             in int depth, in byte[] subject, in byte[] certHash, in byte[] certBlob);
 }
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
index c163864..2ed6a0e 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
@@ -33,6 +33,7 @@
 using aidl::android::hardware::wifi::supplicant::ConnectionCapabilities;
 using aidl::android::hardware::wifi::supplicant::DebugLevel;
 using aidl::android::hardware::wifi::supplicant::DppAkm;
+using aidl::android::hardware::wifi::supplicant::DppConnectionKeys;
 using aidl::android::hardware::wifi::supplicant::DppCurve;
 using aidl::android::hardware::wifi::supplicant::DppNetRole;
 using aidl::android::hardware::wifi::supplicant::DppResponderBootstrapInfo;
@@ -78,6 +79,13 @@
         const std::vector<uint8_t>& /* bssid */) override {
         return ndk::ScopedAStatus::ok();
     }
+    ::ndk::ScopedAStatus onAuxiliarySupplicantEvent(
+            ::aidl::android::hardware::wifi::supplicant ::
+                    AuxiliarySupplicantEventCode /* eventCode */,
+            const std::vector<uint8_t>& /* bssid */,
+            const std::string& /* reasonString */) override {
+        return ndk::ScopedAStatus::ok();
+    }
     ::ndk::ScopedAStatus onBssTmHandlingDone(
         const ::aidl::android::hardware::wifi::supplicant::
             BssTmData& /* tmData */) override {
@@ -112,17 +120,18 @@
         return ndk::ScopedAStatus::ok();
     }
     ::ndk::ScopedAStatus onDppSuccessConfigReceived(
-        const std::vector<uint8_t>& /* ssid */,
-        const std::string& /* password */,
-        const std::vector<uint8_t>& /* psk */,
-        ::aidl::android::hardware::wifi::supplicant::DppAkm /* securityAkm */)
-        override {
+            const std::vector<uint8_t>& /* ssid */, const std::string& /* password */,
+            const std::vector<uint8_t>& /* psk */,
+            ::aidl::android::hardware::wifi::supplicant::DppAkm /* securityAkm */,
+            const ::aidl::android::hardware::wifi::supplicant::
+                    DppConnectionKeys& /* DppConnectionKeys */) override {
         return ndk::ScopedAStatus::ok();
     }
     ::ndk::ScopedAStatus onDppSuccessConfigSent() override {
         return ndk::ScopedAStatus::ok();
     }
-    ::ndk::ScopedAStatus onEapFailure(int32_t /* errorCode */) override {
+    ::ndk::ScopedAStatus onEapFailure(const std::vector<uint8_t>& /* bssid */,
+                                      int32_t /* errorCode */) override {
         return ndk::ScopedAStatus::ok();
     }
     ::ndk::ScopedAStatus onExtRadioWorkStart(int32_t /* id */) override {
@@ -193,6 +202,7 @@
     }
     ::ndk::ScopedAStatus onQosPolicyReset() override { return ndk::ScopedAStatus::ok(); }
     ::ndk::ScopedAStatus onQosPolicyRequest(
+            int32_t /* qosPolicyRequestId */,
             const std::vector<::aidl::android::hardware::wifi::supplicant ::
                                       QosPolicyData /* qosPolicyData */>&) override {
         return ndk::ScopedAStatus::ok();
@@ -755,14 +765,16 @@
         "6D795F746573745F73736964";  // 'my_test_ssid' encoded in hex
     const std::string password =
         "746F70736563726574";  // 'topsecret' encoded in hex
+    const std::vector<uint8_t> eckey_in = {0x2, 0x3, 0x4};
+    std::vector<uint8_t> eckey_out = {};
 
     // Start DPP as Configurator-Initiator. Since this operation requires two
     // devices, we start the operation and expect a timeout.
     EXPECT_TRUE(sta_iface_
-                    ->startDppConfiguratorInitiator(peer_id, 0, ssid, password,
-                                                    "", DppNetRole::STA,
-                                                    DppAkm::PSK)
-                    .isOk());
+                        ->startDppConfiguratorInitiator(peer_id, 0, ssid, password, "",
+                                                        DppNetRole::STA, DppAkm::PSK, eckey_in,
+                                                        &eckey_out)
+                        .isOk());
 
     // Wait for the timeout callback
     ASSERT_EQ(std::cv_status::no_timeout,