Merge "Remove GnssHidlHal from default implementation" into tm-dev
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/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/tests/fuzzer/Android.bp b/automotive/can/1.0/default/tests/fuzzer/Android.bp
new file mode 100644
index 0000000..6f19631
--- /dev/null
+++ b/automotive/can/1.0/default/tests/fuzzer/Android.bp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+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.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/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/TEST_MAPPING b/automotive/vehicle/TEST_MAPPING
index 92cab96..ff6f3be 100644
--- a/automotive/vehicle/TEST_MAPPING
+++ b/automotive/vehicle/TEST_MAPPING
@@ -24,10 +24,5 @@
     {
       "name": "DefaultVehicleHalTest"
     }
-  ],
-  "auto-postsubmit": [
-    {
-      "name": "AndroidCarApiTest"
-    }
   ]
 }
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..fa494c6 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 = android::base::Result<VehiclePropValuePool::RecyclableType, VhalError>;
+
     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(
+    android::base::Result<void, VhalError> 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(
+    android::base::Result<void, VhalError> 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(
+    android::base::Result<void, VhalError> setApPowerStateReport(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
     VehiclePropValuePool::RecyclableType createApPowerStateReq(
             aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq state);
-    android::base::Result<void> setUserHalProp(
+    android::base::Result<void, VhalError> 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..233efc8 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -68,6 +68,8 @@
 using ::android::base::StartsWith;
 using ::android::base::StringPrintf;
 
+using StatusError = android::base::Error<VhalError>;
+
 const char* VENDOR_OVERRIDE_DIR = "/vendor/etc/automotive/vhaloverride/";
 const char* OVERRIDE_PROPERTY = "persist.vendor.vhal_init_value_override";
 
@@ -191,13 +193,13 @@
     return req;
 }
 
-Result<void> FakeVehicleHardware::setApPowerStateReport(const VehiclePropValue& value) {
+Result<void, VhalError> 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 +213,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 +243,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 +270,10 @@
     return false;
 }
 
-Result<void> FakeVehicleHardware::setUserHalProp(const VehiclePropValue& value) {
+Result<void, VhalError> 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 +282,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 +290,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 +306,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 +345,8 @@
     return nullptr;
 }
 
-Result<void> FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValue& value,
-                                                       bool* isSpecialValue) {
+Result<void, VhalError> FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValue& value,
+                                                                  bool* isSpecialValue) {
     *isSpecialValue = false;
     VehiclePropValuePool::RecyclableType updatedValue;
     int32_t propId = value.prop;
@@ -351,7 +358,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 +397,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 +442,13 @@
     return StatusCode::OK;
 }
 
-Result<void> FakeVehicleHardware::setValue(const VehiclePropValue& value) {
+Result<void, VhalError> 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 +461,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 +502,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 +520,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 3dae9fc..6259f96 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -924,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..ba40f60 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(
+    android::base::Result<VehiclePropValuePool::RecyclableType, VhalError> getObd2FreezeFrame(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue&
                     requestedPropValue) const;
-    android::base::Result<VehiclePropValuePool::RecyclableType> getObd2DtcInfo() const;
-    android::base::Result<void> clearObd2FreezeFrames(
+    android::base::Result<VehiclePropValuePool::RecyclableType, VhalError> getObd2DtcInfo() const;
+    android::base::Result<void, VhalError> 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..0a4affc 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/src/FakeObd2Frame.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/src/FakeObd2Frame.cpp
@@ -44,9 +44,10 @@
 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;
 
+using StatusError = android::base::Error<VhalError>;
+
 std::unique_ptr<Obd2SensorStore> FakeObd2Frame::fillDefaultObd2Frame(size_t numVendorIntegerSensors,
                                                                      size_t numVendorFloatSensors) {
     std::unique_ptr<Obd2SensorStore> sensorStore(new Obd2SensorStore(
@@ -126,37 +127,37 @@
     }
 }
 
-Result<VehiclePropValuePool::RecyclableType> FakeObd2Frame::getObd2FreezeFrame(
+Result<VehiclePropValuePool::RecyclableType, VhalError> 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 {
+Result<VehiclePropValuePool::RecyclableType, VhalError> 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 +170,7 @@
     return outValue;
 }
 
-Result<void> FakeObd2Frame::clearObd2FreezeFrames(const VehiclePropValue& propValue) {
+Result<void, VhalError> FakeObd2Frame::clearObd2FreezeFrames(const VehiclePropValue& propValue) {
     if (propValue.value.int64Values.size() == 0) {
         mPropStore->removeValuesForProperty(OBD2_FREEZE_FRAME);
         return {};
@@ -177,7 +178,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..9c4887c 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 = android::base::Result<VehiclePropValuePool::RecyclableType, VhalError>;
+
     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..e37f619 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
@@ -44,6 +44,8 @@
 using ::android::base::Error;
 using ::android::base::Result;
 
+using StatusError = android::base::Error<VhalError>;
+
 constexpr int32_t INITIAL_USER_INFO = toInt(VehicleProperty::INITIAL_USER_INFO);
 constexpr int32_t SWITCH_USER = toInt(VehicleProperty::SWITCH_USER);
 constexpr int32_t CREATE_USER = toInt(VehicleProperty::CREATE_USER);
@@ -51,20 +53,24 @@
 constexpr int32_t USER_IDENTIFICATION_ASSOCIATION =
         toInt(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
 
-Result<int32_t> getRequestId(const VehiclePropValue& value) {
+Result<int32_t, VhalError> 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) {
+Result<SwitchUserMessageType, VhalError> 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 +88,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 +104,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 +117,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 +147,7 @@
     return newValue;
 }
 
-Result<VehiclePropValuePool::RecyclableType> FakeUserHal::onSetInitialUserInfoResponse(
+FakeUserHal::ValueResultType FakeUserHal::onSetInitialUserInfoResponse(
         const VehiclePropValue& value) {
     std::scoped_lock<std::mutex> lockGuard(mLock);
 
@@ -178,8 +182,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 +237,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 +270,7 @@
     return updatedValue;
 }
 
-Result<VehiclePropValuePool::RecyclableType> FakeUserHal::onSetUserIdentificationAssociation(
+FakeUserHal::ValueResultType FakeUserHal::onSetUserIdentificationAssociation(
         const VehiclePropValue& value) {
     std::scoped_lock<std::mutex> lockGuard(mLock);
 
@@ -298,14 +300,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 +321,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/PendingRequestPool.h b/automotive/vehicle/aidl/impl/utils/common/include/PendingRequestPool.h
index dcf5057..4ab8acd 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);
+    android::base::Result<void, VhalError> 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..cebf95c 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,10 @@
 // This class is thread-safe, however it uses blocking synchronization across all methods.
 class VehiclePropertyStore final {
   public:
+    using ValueResultType = android::base::Result<VehiclePropValuePool::RecyclableType, VhalError>;
+    using ValuesResultType =
+            android::base::Result<std::vector<VehiclePropValuePool::RecyclableType>, VhalError>;
+
     explicit VehiclePropertyStore(std::shared_ptr<VehiclePropValuePool> valuePool)
         : mValuePool(valuePool) {}
 
@@ -68,8 +73,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);
+    android::base::Result<void, VhalError> 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 +88,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 +149,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..8ef0218 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,79 @@
         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;
+};
+
+template <class T>
+aidl::android::hardware::automotive::vehicle::StatusCode getErrorCode(
+        const android::base::Result<T, VhalError>& result) {
+    if (result.ok()) {
+        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+    }
+    return result.error().code();
+}
+
+template <class T>
+int getIntErrorCode(const android::base::Result<T, VhalError>& 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 android::base::Result<T, VhalError>& result) {
+    return toScopedAStatus(result, getErrorCode(result));
+}
+
+template <class T>
+ndk::ScopedAStatus toScopedAStatus(const android::base::Result<T, VhalError>& 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..f8a042d 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/PendingRequestPool.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/PendingRequestPool.cpp
@@ -32,11 +32,12 @@
 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;
+
+using StatusError = android::base::Error<VhalError>;
 
 }  // namespace
 
@@ -72,9 +73,9 @@
     }
 }
 
-Result<void> PendingRequestPool::addRequests(const void* clientId,
-                                             const std::unordered_set<int64_t>& requestIds,
-                                             std::shared_ptr<const TimeoutCallbackFunc> callback) {
+Result<void, VhalError> 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 +85,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 +97,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..776caed 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -36,10 +36,11 @@
 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;
 
+using StatusError = android::base::Error<VhalError>;
+
 bool VehiclePropertyStore::RecordId::operator==(const VehiclePropertyStore::RecordId& other) const {
     return area == other.area && token == other.token;
 }
@@ -87,12 +88,12 @@
     return recId;
 }
 
-Result<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readValueLocked(
+Result<VehiclePropValuePool::RecyclableType, VhalError> 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 +107,19 @@
     };
 }
 
-Result<void> VehiclePropertyStore::writeValue(VehiclePropValuePool::RecyclableType propValue,
-                                              bool updateStatus) {
+Result<void, VhalError> 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 +131,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 +192,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 +209,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 +248,12 @@
     return configs;
 }
 
-Result<const VehiclePropConfig*> VehiclePropertyStore::getConfig(int32_t propId) const {
+Result<const VehiclePropConfig*, VhalError> 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..c8bf1d8 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
@@ -103,7 +103,7 @@
 }
 
 TEST_F(VehiclePropertyStoreTest, testGetConfig) {
-    Result<const VehiclePropConfig*> result =
+    Result<const VehiclePropConfig*, VhalError> result =
             mStore->getConfig(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
 
     ASSERT_RESULT_OK(result);
@@ -111,10 +111,10 @@
 }
 
 TEST_F(VehiclePropertyStoreTest, testGetConfigWithInvalidPropId) {
-    Result<const VehiclePropConfig*> result = mStore->getConfig(INVALID_PROP_ID);
+    Result<const VehiclePropConfig*, VhalError> 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 +184,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 +224,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 +235,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 +248,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 +269,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 +317,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..cc29964 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) {
+    Result<void, VhalError> 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..6ab0e1e 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,8 @@
     // 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);
+    android::base::Result<void, VhalError> 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..84b6742 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -43,6 +43,7 @@
   public:
     using CallbackType =
             std::shared_ptr<aidl::android::hardware::automotive::vehicle::IVehicleCallback>;
+    using StatusError = android::base::Error<VhalError>;
 
     explicit DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware);
 
@@ -189,14 +190,14 @@
             const std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>&
                     requests);
 
-    android::base::Result<void> checkSubscribeOptions(
+    android::base::Result<void, VhalError> checkSubscribeOptions(
             const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
                     options);
 
-    android::base::Result<void> checkReadPermission(
+    android::base::Result<void, VhalError> checkReadPermission(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
 
-    android::base::Result<void> checkWritePermission(
+    android::base::Result<void, VhalError> checkWritePermission(
             const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
 
     android::base::Result<const aidl::android::hardware::automotive::vehicle::VehiclePropConfig*>
diff --git a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
index 098bfee..5c5f27e 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
@@ -67,7 +67,8 @@
     parcelableResults.payloads[0] = result;
     if (ScopedAStatus callbackStatus = callCallback(callback, parcelableResults);
         !callbackStatus.isOk()) {
-        ALOGE("failed to call callback, error: %s, code: %d", callbackStatus.getMessage(),
+        ALOGE("failed to call callback, error: %s, exception: %d, service specific error: %d",
+              callbackStatus.getMessage(), callbackStatus.getExceptionCode(),
               callbackStatus.getServiceSpecificError());
     }
 }
@@ -90,8 +91,9 @@
     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 callback, error: %s, exception: %d, service specific error: %d",
+                  callbackStatus.getMessage(), callbackStatus.getExceptionCode(),
+                  callbackStatus.getServiceSpecificError());
         }
         return;
     }
@@ -192,7 +194,8 @@
     return reinterpret_cast<const void*>(this);
 }
 
-Result<void> ConnectedClient::addRequests(const std::unordered_set<int64_t>& requestIds) {
+Result<void, VhalError> ConnectedClient::addRequests(
+        const std::unordered_set<int64_t>& requestIds) {
     return mRequestPool->addRequests(id(), requestIds, getTimeoutCallback());
 }
 
@@ -296,8 +299,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 callback, error: %s, exception: %d, "
+              "service specific error: %d",
+              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..b50571b 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -115,7 +115,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;
     }
 
@@ -218,6 +218,7 @@
 }
 
 void DefaultVehicleHal::onBinderDiedWithContext(const AIBinder* clientId) {
+    ALOGD("binder died");
     std::scoped_lock<std::mutex> lockGuard(mLock);
     mSetValuesClients.erase(clientId);
     mGetValuesClients.erase(clientId);
@@ -232,6 +233,7 @@
 }
 
 void DefaultVehicleHal::onBinderUnlinkedWithContext(const AIBinder* clientId) {
+    ALOGD("binder unlinked");
     std::scoped_lock<std::mutex> lockGuard(mLock);
     mOnBinderDiedContexts.erase(clientId);
 }
@@ -473,7 +475,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 +536,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(
+Result<void, VhalError> 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 +572,12 @@
             float minSampleRate = config.minSampleRate;
             float maxSampleRate = config.maxSampleRate;
             if (sampleRate < minSampleRate || sampleRate > maxSampleRate) {
-                return Error(toInt(StatusCode::INVALID_ARG))
+                return StatusError(StatusCode::INVALID_ARG)
                        << StringPrintf("sample rate: %f out of range, must be within %f and %f",
                                        sampleRate, minSampleRate, maxSampleRate);
             }
             if (!SubscriptionManager::checkSampleRate(sampleRate)) {
-                return Error(toInt(StatusCode::INVALID_ARG))
+                return StatusError(StatusCode::INVALID_ARG)
                        << "invalid sample rate: " << sampleRate;
             }
         }
@@ -583,7 +589,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);
@@ -656,33 +662,35 @@
     return mVehicleHardware.get();
 }
 
-Result<void> DefaultVehicleHal::checkWritePermission(const VehiclePropValue& value) const {
+Result<void, VhalError> 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 {
+Result<void, VhalError> 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 {};
diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index 178498b..aafa17e 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
@@ -514,6 +514,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;
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/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/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/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 0033fee..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,7 +35,7 @@
 @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);
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/IBluetoothAudioPort.aidl
index 9f8007b..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
diff --git a/bluetooth/audio/aidl/vts/Android.bp b/bluetooth/audio/aidl/vts/Android.bp
index a662aaa..feb952e 100644
--- a/bluetooth/audio/aidl/vts/Android.bp
+++ b/bluetooth/audio/aidl/vts/Android.bp
@@ -13,6 +13,7 @@
         "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
     ],
+    tidy_timeout_srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
     srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
     shared_libs: [
         "android.hardware.audio.common-V1-ndk",
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
index 0407751..18352a0 100644
--- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -138,7 +138,7 @@
  public:
   BluetoothAudioPort() {}
 
-  ndk::ScopedAStatus startStream() { return ScopedAStatus::ok(); }
+  ndk::ScopedAStatus startStream(bool) { return ScopedAStatus::ok(); }
 
   ndk::ScopedAStatus suspendStream() { return ScopedAStatus::ok(); }
 
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index 7187828..e700e7e 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -198,7 +198,7 @@
                << " has NO session";
     return false;
   }
-  auto hal_retval = stack_iface_->startStream();
+  auto hal_retval = stack_iface_->startStream(false);
   if (!hal_retval.isOk()) {
     LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
                  << toString(session_type_) << " failed";
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/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/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/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..0683987 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,
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..3a790b3 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,7 +64,6 @@
   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,
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/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
index d5cd0b4..93d6f13 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
@@ -57,7 +57,6 @@
     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,
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
index 1f388d9..f20a06e 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>
      */
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableDynamicRangeProfilesMap.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableDynamicRangeProfilesMap.aidl
index c0ef8c6..319be75 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableDynamicRangeProfilesMap.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/RequestAvailableDynamicRangeProfilesMap.aidl
@@ -27,7 +27,7 @@
  * @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,
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 7e5e8b2..ab867cd 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -8287,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()) {
@@ -8335,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);
@@ -8364,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();
         }
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..d1fa94e
--- /dev/null
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -0,0 +1,3058 @@
+/*
+ * 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<int32_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("getCameraCharacteristics: 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;
+        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;
+        }
+
+        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*/);
+
+        ::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<int32_t> useCases(kMandatoryUseCases);
+        useCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL + 1);
+
+        std::vector<int32_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 (int32_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..858dfd5
--- /dev/null
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -0,0 +1,2938 @@
+/*
+ * 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<int32_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.i32, entry.data.i32 + entry.count, kMandatoryUseCases[i]) ==
+                entry.data.i32 + 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) {
+                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(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);
+}
+
+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) {
+    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());
+
+    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..1ca457b
--- /dev/null
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -0,0 +1,530 @@
+/*
+ * 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);
+
+    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 6171620..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-1</version>
-        <interface>
-            <name>IBluetoothAudioProvidersFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.bluetooth.audio</name>
         <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/aidl_api/android.hardware.drm/current/android/hardware/drm/CryptoSchemes.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/CryptoSchemes.aidl
index ea736cf..1d3c293 100644
--- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/CryptoSchemes.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/CryptoSchemes.aidl
@@ -35,7 +35,5 @@
 @VintfStability
 parcelable CryptoSchemes {
   List<android.hardware.drm.Uuid> uuids;
-  android.hardware.drm.SecurityLevel minLevel;
-  android.hardware.drm.SecurityLevel maxLevel;
-  List<String> mimeTypes;
+  List<android.hardware.drm.SupportedContentType> mimeTypes;
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTargetPropertyWithNits.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SupportedContentType.aidl
similarity index 82%
copy from graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTargetPropertyWithNits.aidl
copy to drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SupportedContentType.aidl
index f0fb22e..6ef5db8 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTargetPropertyWithNits.aidl
+++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SupportedContentType.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 obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -31,10 +31,10 @@
 // with such a backward incompatible change, it has a high risk of breaking
 // later when a module using the interface is updated, e.g., Mainline modules.
 
-package android.hardware.graphics.composer3;
+package android.hardware.drm;
 @VintfStability
-parcelable ClientTargetPropertyWithNits {
-  long display;
-  android.hardware.graphics.composer3.ClientTargetProperty clientTargetProperty;
-  float whitePointNits;
+parcelable SupportedContentType {
+  String mime;
+  android.hardware.drm.SecurityLevel minLevel;
+  android.hardware.drm.SecurityLevel maxLevel;
 }
diff --git a/drm/aidl/android/hardware/drm/CryptoSchemes.aidl b/drm/aidl/android/hardware/drm/CryptoSchemes.aidl
index b4b34ec..1f251d8 100644
--- a/drm/aidl/android/hardware/drm/CryptoSchemes.aidl
+++ b/drm/aidl/android/hardware/drm/CryptoSchemes.aidl
@@ -16,7 +16,7 @@
 
 package android.hardware.drm;
 
-import android.hardware.drm.SecurityLevel;
+import android.hardware.drm.SupportedContentType;
 import android.hardware.drm.Uuid;
 
 @VintfStability
@@ -28,18 +28,8 @@
     List<Uuid> uuids;
 
     /**
-     * Minimum supported security level (inclusive)
+     * Supported mime types, and supported SecurityLevels for each mime
      */
-    SecurityLevel minLevel;
-
-    /**
-     * Maximum supported security level (inclusive)
-     */
-    SecurityLevel maxLevel;
-
-    /**
-     * Supported mime types
-     */
-    List<String> mimeTypes;
+    List<SupportedContentType> mimeTypes;
 
 }
diff --git a/drm/aidl/android/hardware/drm/SupportedContentType.aidl b/drm/aidl/android/hardware/drm/SupportedContentType.aidl
new file mode 100644
index 0000000..f4fabad
--- /dev/null
+++ b/drm/aidl/android/hardware/drm/SupportedContentType.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.drm;
+
+import android.hardware.drm.SecurityLevel;
+
+@VintfStability
+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/vts/drm_hal_common.cpp b/drm/aidl/vts/drm_hal_common.cpp
index 9b315f4..de7dc28 100644
--- a/drm/aidl/vts/drm_hal_common.cpp
+++ b/drm/aidl/vts/drm_hal_common.cpp
@@ -256,7 +256,7 @@
 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();
 }
@@ -268,17 +268,22 @@
     if (!ret.isOk() || !std::count(schemes.uuids.begin(), schemes.uuids.end(), uuid)) {
         return false;
     }
-    if (level > schemes.maxLevel || level < schemes.minLevel) {
-        if (level != SecurityLevel::DEFAULT && level != SecurityLevel::UNKNOWN) {
-            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;
         }
     }
-    if (!mime.empty()) {
-        if (!std::count(schemes.mimeTypes.begin(), schemes.mimeTypes.end(), mime)) {
-            return false;
-        }
-    }
-    return true;
+    return false;
 }
 
 void DrmHalTest::provision() {
diff --git a/drm/aidl/vts/drm_hal_test.cpp b/drm/aidl/vts/drm_hal_test.cpp
index 266ea39..14b3acf 100644
--- a/drm/aidl/vts/drm_hal_test.cpp
+++ b/drm/aidl/vts/drm_hal_test.cpp
@@ -100,6 +100,19 @@
 }
 
 /**
+ * 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
  */
 
diff --git a/drm/aidl/vts/include/drm_hal_common.h b/drm/aidl/vts/include/drm_hal_common.h
index 2c7e514..d493bed 100644
--- a/drm/aidl/vts/include/drm_hal_common.h
+++ b/drm/aidl/vts/include/drm_hal_common.h
@@ -59,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);
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/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/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/ClientTargetPropertyWithNits.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DimmingStage.aidl
similarity index 87%
copy from graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClientTargetPropertyWithNits.aidl
copy to graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DimmingStage.aidl
index f0fb22e..44457f8 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/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,9 +32,9 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.graphics.composer3;
-@VintfStability
-parcelable ClientTargetPropertyWithNits {
-  long display;
-  android.hardware.graphics.composer3.ClientTargetProperty clientTargetProperty;
-  float whitePointNits;
+@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/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/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/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/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 98%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/GraphicsComposerCallback.cpp
rename to graphics/composer/aidl/vts/GraphicsComposerCallback.cpp
index 8f329b3..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>
 
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 100%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/GraphicsComposerCallback.h
rename to graphics/composer/aidl/vts/GraphicsComposerCallback.h
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 99%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/ReadbackVts.cpp
rename to graphics/composer/aidl/vts/ReadbackVts.cpp
index f8a0ec4..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"
 
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 100%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/ReadbackVts.h
rename to graphics/composer/aidl/vts/ReadbackVts.h
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 97%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/VtsComposerClient.cpp
rename to graphics/composer/aidl/vts/VtsComposerClient.cpp
index b3b10d0..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(
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 100%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/VtsComposerClient.h
rename to graphics/composer/aidl/vts/VtsComposerClient.h
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 95%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp
rename to graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 8f88bfc..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 {
@@ -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;
@@ -264,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;
@@ -316,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;
@@ -376,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;
@@ -425,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;
@@ -439,8 +440,8 @@
 }
 
 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;
@@ -461,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;
@@ -478,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;
@@ -503,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;
@@ -594,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;
@@ -693,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;
@@ -768,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;
@@ -819,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;
@@ -878,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;
@@ -982,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: "
@@ -1050,7 +1051,10 @@
         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 = {ColorMode::SRGB};
+        mTestColorModes.erase(
+                std::remove_if(mTestColorModes.begin(), mTestColorModes.end(),
+                               [](ColorMode mode) { return mode != ColorMode::SRGB; }),
+                mTestColorModes.end());
         mBackgroundColor = BLACK;
         mTopLayerColor = RED;
     }
@@ -1135,8 +1139,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;
@@ -1179,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;
@@ -1220,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;
@@ -1303,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;
@@ -1348,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;
@@ -1393,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 98%
rename from graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
rename to graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index f327381..bfb6b85 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -35,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"
@@ -1627,10 +1627,8 @@
 
         const auto [error, support] =
                 mComposerClient->getDisplayDecorationSupport(display.getDisplayId());
-        EXPECT_TRUE(error.isOk());
 
-        const auto format =
-                support ? support->format
+        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);
@@ -1657,12 +1655,7 @@
         } else {
             const auto errors = mReader.takeErrors();
             ASSERT_EQ(1, errors.size());
-            EXPECT_EQ(EX_UNSUPPORTED_OPERATION, errors[0].errorCode);
-
-            const auto changedTypes = mReader.takeChangedCompositionTypes(display.getDisplayId());
-            ASSERT_EQ(1u, changedTypes.size());
-            const auto changedType = changedTypes[0].composition;
-            EXPECT_TRUE(changedType == Composition::DEVICE || changedType == Composition::CLIENT);
+            EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, errors[0].errorCode);
         }
     }
 }
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/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/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/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/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/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/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/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/radio/aidl/vts/Android.bp b/radio/aidl/vts/Android.bp
index d5bf21c..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",
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.cpp b/radio/aidl/vts/radio_aidl_hal_utils.cpp
index dc61a3c..1f73930 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;
 
@@ -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..a124907 100644
--- a/radio/aidl/vts/radio_config_test.cpp
+++ b/radio/aidl/vts/radio_config_test.cpp
@@ -44,6 +44,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 +166,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 e82235c..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);
+        }
     }
 }
 
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.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/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/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 6263c0a..38abe81 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
@@ -1598,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,
diff --git a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
new file mode 100644
index 0000000..83ee188
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
@@ -0,0 +1,255 @@
+/*
+ * 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) {
+    // 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) {
+    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) {
+    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) return;
+
+    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) return;  // Need a StrongBox to provision.
+
+    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) return;  // Need a StrongBox to provision.
+
+    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) return;  // Need a StrongBox to provision.
+
+    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) return;  // Need a StrongBox to provision.
+
+    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..2e90e78 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,11 +359,10 @@
 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_);
+        auto chain = generateEekChain(rpcHardwareInfo.supportedEekCurve, eekLength, eekId_);
         EXPECT_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());
 }
 
@@ -662,6 +674,7 @@
     bytevec keysToSignMac;
     DeviceInfo deviceInfo;
     ProtectedData protectedData;
+    generateTestEekChain(3);
     auto status = provisionable_->generateCertificateRequest(
             testMode, {keyWithCorruptMac}, testEekChain_.chain, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
@@ -681,8 +694,8 @@
     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 +708,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 +739,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 +767,7 @@
     bytevec keysToSignMac;
     DeviceInfo deviceInfo;
     ProtectedData protectedData;
+    generateTestEekChain(3);
     auto status = provisionable_->generateCertificateRequest(
             true /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
             &protectedData, &keysToSignMac);
@@ -772,6 +786,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..1d3abe5 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;
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index 35cb891..0776282 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) 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) 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();
diff --git a/security/keymint/support/remote_prov_utils_test.cpp b/security/keymint/support/remote_prov_utils_test.cpp
index 8697c51..e1c4467 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()));
@@ -97,5 +196,57 @@
     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/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/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/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/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.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.6/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp
index eaab211..81117c5 100644
--- a/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp
+++ b/wifi/1.6/default/tests/wifi_chip_unit_tests.cpp
@@ -846,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/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.6/vts/functional/wifi_chip_hidl_test.cpp
index 54fb721..7c5b7e6 100644
--- a/wifi/1.6/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.6/vts/functional/wifi_chip_hidl_test.cpp
@@ -91,6 +91,34 @@
     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);
 }
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
index bf9e230..46a1314 100644
--- a/wifi/1.6/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.6/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -604,6 +604,92 @@
     }
 }
 
+/*
+ * 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);
+
+    // 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_6InvalidArgs: validate that fails with invalid arguments
+ */
+TEST_P(WifiNanIfaceHidlTest, startPublishRequest_1_6InvalidArgs) {
+    uint16_t inputCmdId = 10;
+    callbackType = INVALID;
+    ::android::hardware::wifi::V1_6::NanPublishRequest nanPublishRequest = {};
+    const auto& halStatus =
+            HIDL_INVOKE(iwifiNanIface, startPublishRequest_1_6, inputCmdId, nanPublishRequest);
+
+    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_START_PUBLISH_RESPONSE));
+        ASSERT_EQ(NOTIFY_START_PUBLISH_RESPONSE, callbackType);
+        ASSERT_EQ(id, inputCmdId);
+        ASSERT_EQ(status.status, NanStatusType::INTERNAL_FAILURE);
+    }
+}
+
+/*
+ * 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(
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/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/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 46c8000..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
@@ -46,7 +46,7 @@
   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, 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);
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
index 895bc50..0730a8c 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -154,11 +154,12 @@
 
     /**
      * 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.
      */
-    void onEapFailure(in int errorCode);
+    void onEapFailure(in byte[] bssid, in int errorCode);
 
     /**
      * Used to indicate that the external radio work can start now.
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 1c00ec7..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
@@ -130,7 +130,8 @@
     ::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 {