Merge "Add automotive related keys to AIDL." into tm-dev
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..52b43b0
--- /dev/null
+++ b/automotive/can/1.0/default/tests/fuzzer/Android.bp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_fuzz {
+    name: "automotiveCanV1.0_fuzzer",
+    vendor: true,
+    defaults: ["android.hardware.automotive.can@defaults"],
+    srcs: [
+        "AutomotiveCanV1_0Fuzzer.cpp",
+        ":automotiveCanV1.0_sources",
+    ],
+    header_libs: [
+        "automotiveCanV1.0_headers",
+        "android.hardware.automotive.can@hidl-utils-lib",
+    ],
+    shared_libs: [
+        "android.hardware.automotive.can@1.0",
+        "libhidlbase",
+    ],
+    static_libs: [
+        "android.hardware.automotive.can@libnetdevice",
+        "android.hardware.automotive@libc++fs",
+        "libnl++",
+    ],
+    fuzz_config: {
+        cc: [
+            "android-media-fuzzing-reports@google.com",
+        ],
+        componentid: 533764,
+    },
+}
diff --git a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp
new file mode 100644
index 0000000..96110db
--- /dev/null
+++ b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include "AutomotiveCanV1_0Fuzzer.h"
+
+namespace android::hardware::automotive::can::V1_0::implementation::fuzzer {
+
+constexpr CanController::InterfaceType kInterfaceType[] = {CanController::InterfaceType::VIRTUAL,
+                                                           CanController::InterfaceType::SOCKETCAN,
+                                                           CanController::InterfaceType::SLCAN};
+constexpr FilterFlag kFilterFlag[] = {FilterFlag::DONT_CARE, FilterFlag::SET, FilterFlag::NOT_SET};
+constexpr size_t kInterfaceTypeLength = std::size(kInterfaceType);
+constexpr size_t kFilterFlagLength = std::size(kFilterFlag);
+constexpr size_t kMaxCharacters = 30;
+constexpr size_t kMaxPayloadBytes = 64;
+constexpr size_t kMaxFilters = 20;
+constexpr size_t kMaxSerialNumber = 1000;
+constexpr size_t kMaxBuses = 10;
+constexpr size_t kMaxRepeat = 5;
+
+Bus CanFuzzer::makeBus() {
+    ICanController::BusConfig config = {};
+    if (mBusNames.size() > 0 && mLastInterface < mBusNames.size()) {
+        config.name = mBusNames[mLastInterface++];
+    } else {
+        config.name = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters);
+    }
+    config.interfaceId.virtualif({mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters)});
+    return Bus(mCanController, config);
+}
+
+void CanFuzzer::getSupportedInterfaceTypes() {
+    hidl_vec<CanController::InterfaceType> iftypesResult;
+    mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&iftypesResult));
+}
+
+hidl_vec<hidl_string> CanFuzzer::getBusNames() {
+    hidl_vec<hidl_string> services = {};
+    if (auto manager = hidl::manager::V1_2::IServiceManager::getService(); manager) {
+        manager->listManifestByInterface(ICanBus::descriptor, hidl_utils::fill(&services));
+    }
+    return services;
+}
+
+void CanFuzzer::invokeUpInterface() {
+    const CanController::InterfaceType iftype =
+            kInterfaceType[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+                    0, kInterfaceTypeLength - 1)];
+    std::string configName;
+
+    if (const bool shouldInvokeValidBus = mFuzzedDataProvider->ConsumeBool();
+        (shouldInvokeValidBus) && (mBusNames.size() > 0)) {
+        const size_t busNameIndex =
+                mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, mBusNames.size() - 1);
+        configName = mBusNames[busNameIndex];
+    } else {
+        configName = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters);
+    }
+    const std::string ifname = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters);
+
+    ICanController::BusConfig config = {.name = configName};
+
+    if (iftype == CanController::InterfaceType::SOCKETCAN) {
+        CanController::BusConfig::InterfaceId::Socketcan socketcan = {};
+        if (const bool shouldPassSerialSocket = mFuzzedDataProvider->ConsumeBool();
+            shouldPassSerialSocket) {
+            socketcan.serialno(
+                    {mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kMaxSerialNumber)});
+        } else {
+            socketcan.ifname(ifname);
+        }
+        config.interfaceId.socketcan(socketcan);
+    } else if (iftype == CanController::InterfaceType::SLCAN) {
+        CanController::BusConfig::InterfaceId::Slcan slcan = {};
+        if (const bool shouldPassSerialSlcan = mFuzzedDataProvider->ConsumeBool();
+            shouldPassSerialSlcan) {
+            slcan.serialno(
+                    {mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kMaxSerialNumber)});
+        } else {
+            slcan.ttyname(ifname);
+        }
+        config.interfaceId.slcan(slcan);
+    } else if (iftype == CanController::InterfaceType::VIRTUAL) {
+        config.interfaceId.virtualif({ifname});
+    }
+
+    const size_t numInvocations =
+            mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, kMaxRepeat);
+    for (size_t i = 0; i < numInvocations; ++i) {
+        mCanController->upInterface(config);
+    }
+}
+
+void CanFuzzer::invokeDownInterface() {
+    hidl_string configName;
+    if (const bool shouldInvokeValidBus = mFuzzedDataProvider->ConsumeBool();
+        (shouldInvokeValidBus) && (mBusNames.size() > 0)) {
+        const size_t busNameIndex =
+                mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, mBusNames.size() - 1);
+        configName = mBusNames[busNameIndex];
+    } else {
+        configName = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxCharacters);
+    }
+
+    const size_t numInvocations =
+            mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(0, kMaxRepeat);
+    for (size_t i = 0; i < numInvocations; ++i) {
+        mCanController->downInterface(configName);
+    }
+}
+
+void CanFuzzer::invokeController() {
+    getSupportedInterfaceTypes();
+    invokeUpInterface();
+    invokeDownInterface();
+}
+
+void CanFuzzer::invokeBus() {
+    const size_t numBuses = mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(1, kMaxBuses);
+    for (size_t i = 0; i < numBuses; ++i) {
+        if (const bool shouldSendMessage = mFuzzedDataProvider->ConsumeBool(); shouldSendMessage) {
+            auto sendingBus = makeBus();
+            CanMessage msg = {.id = mFuzzedDataProvider->ConsumeIntegral<uint32_t>()};
+            uint32_t numPayloadBytes =
+                    mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(0, kMaxPayloadBytes);
+            hidl_vec<uint8_t> payload(numPayloadBytes);
+            for (uint32_t j = 0; j < numPayloadBytes; ++j) {
+                payload[j] = mFuzzedDataProvider->ConsumeIntegral<uint32_t>();
+            }
+            msg.payload = payload;
+            msg.remoteTransmissionRequest = mFuzzedDataProvider->ConsumeBool();
+            msg.isExtendedId = mFuzzedDataProvider->ConsumeBool();
+            sendingBus.send(msg);
+        } else {
+            auto listeningBus = makeBus();
+            uint32_t numFilters =
+                    mFuzzedDataProvider->ConsumeIntegralInRange<uint32_t>(1, kMaxFilters);
+            hidl_vec<CanMessageFilter> filterVector(numFilters);
+            for (uint32_t k = 0; k < numFilters; ++k) {
+                filterVector[k].id = mFuzzedDataProvider->ConsumeIntegral<uint32_t>();
+                filterVector[k].mask = mFuzzedDataProvider->ConsumeIntegral<uint32_t>();
+                filterVector[k].rtr =
+                        kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+                                0, kFilterFlagLength - 1)];
+                filterVector[k].extendedFormat =
+                        kFilterFlag[mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(
+                                0, kFilterFlagLength - 1)];
+                filterVector[k].exclude = mFuzzedDataProvider->ConsumeBool();
+            }
+            auto listener = listeningBus.listen(filterVector);
+        }
+    }
+}
+
+void CanFuzzer::deInit() {
+    mCanController.clear();
+    if (mFuzzedDataProvider) {
+        delete mFuzzedDataProvider;
+    }
+    mBusNames = {};
+}
+
+void CanFuzzer::process(const uint8_t* data, size_t size) {
+    mFuzzedDataProvider = new FuzzedDataProvider(data, size);
+    invokeController();
+    invokeBus();
+}
+
+bool CanFuzzer::init() {
+    mCanController = sp<CanController>::make();
+    if (!mCanController) {
+        return false;
+    }
+    mBusNames = getBusNames();
+    return true;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    if (size < 1) {
+        return 0;
+    }
+    CanFuzzer canFuzzer;
+    if (canFuzzer.init()) {
+        canFuzzer.process(data, size);
+    }
+    return 0;
+}
+
+}  // namespace android::hardware::automotive::can::V1_0::implementation::fuzzer
diff --git a/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h
new file mode 100644
index 0000000..930cddd
--- /dev/null
+++ b/automotive/can/1.0/default/tests/fuzzer/AutomotiveCanV1_0Fuzzer.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#ifndef __AUTOMOTIVE_CAN_V1_0_FUZZER_H__
+#define __AUTOMOTIVE_CAN_V1_0_FUZZER_H__
+#include <CanController.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <hidl-utils/hidl-utils.h>
+
+namespace android::hardware::automotive::can::V1_0::implementation::fuzzer {
+
+using ::android::sp;
+
+struct CanMessageListener : public can::V1_0::ICanMessageListener {
+    DISALLOW_COPY_AND_ASSIGN(CanMessageListener);
+
+    CanMessageListener() {}
+
+    virtual Return<void> onReceive(const can::V1_0::CanMessage& msg) override {
+        std::unique_lock<std::mutex> lock(mMessagesGuard);
+        mMessages.push_back(msg);
+        mMessagesUpdated.notify_one();
+        return {};
+    }
+
+    virtual ~CanMessageListener() {
+        if (mCloseHandle) {
+            mCloseHandle->close();
+        }
+    }
+
+    void assignCloseHandle(sp<ICloseHandle> closeHandle) { mCloseHandle = closeHandle; }
+
+  private:
+    sp<ICloseHandle> mCloseHandle;
+
+    std::mutex mMessagesGuard;
+    std::condition_variable mMessagesUpdated GUARDED_BY(mMessagesGuard);
+    std::vector<can::V1_0::CanMessage> mMessages GUARDED_BY(mMessagesGuard);
+};
+
+struct Bus {
+    DISALLOW_COPY_AND_ASSIGN(Bus);
+
+    Bus(sp<ICanController> controller, const ICanController::BusConfig& config)
+        : mIfname(config.name), mController(controller) {
+        const auto result = controller->upInterface(config);
+        const auto manager = hidl::manager::V1_2::IServiceManager::getService();
+        const auto service = manager->get(ICanBus::descriptor, config.name);
+        mBus = ICanBus::castFrom(service);
+    }
+
+    virtual ~Bus() { reset(); }
+
+    void reset() {
+        mBus.clear();
+        if (mController) {
+            mController->downInterface(mIfname);
+            mController.clear();
+        }
+    }
+
+    ICanBus* operator->() const { return mBus.get(); }
+    sp<ICanBus> get() { return mBus; }
+
+    sp<CanMessageListener> listen(const hidl_vec<CanMessageFilter>& filter) {
+        sp<CanMessageListener> listener = sp<CanMessageListener>::make();
+
+        if (!mBus) {
+            return listener;
+        }
+        Result result;
+        sp<ICloseHandle> closeHandle;
+        mBus->listen(filter, listener, hidl_utils::fill(&result, &closeHandle)).assertOk();
+        listener->assignCloseHandle(closeHandle);
+
+        return listener;
+    }
+
+    void send(const CanMessage& msg) {
+        if (!mBus) {
+            return;
+        }
+        mBus->send(msg);
+    }
+
+  private:
+    const std::string mIfname;
+    sp<ICanController> mController;
+    sp<ICanBus> mBus;
+};
+
+class CanFuzzer {
+  public:
+    ~CanFuzzer() { deInit(); }
+    bool init();
+    void process(const uint8_t* data, size_t size);
+    void deInit();
+
+  private:
+    Bus makeBus();
+    hidl_vec<hidl_string> getBusNames();
+    void getSupportedInterfaceTypes();
+    void invokeBus();
+    void invokeController();
+    void invokeUpInterface();
+    void invokeDownInterface();
+    FuzzedDataProvider* mFuzzedDataProvider = nullptr;
+    sp<CanController> mCanController = nullptr;
+    hidl_vec<hidl_string> mBusNames = {};
+    unsigned mLastInterface = 0;
+};
+}  // namespace android::hardware::automotive::can::V1_0::implementation::fuzzer
+
+#endif  // __AUTOMOTIVE_CAN_V1_0_FUZZER_H__
diff --git a/automotive/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 a78d989..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);
     }
 
@@ -224,7 +226,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);
             }
@@ -241,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);
             }
@@ -268,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();
@@ -280,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);
         }
@@ -288,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();
@@ -304,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;
@@ -344,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;
@@ -357,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) {
@@ -396,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);
             }
@@ -441,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());
         }
@@ -460,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());
     }
@@ -501,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 {
@@ -519,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/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/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 830b936..5c5f27e 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
@@ -194,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());
 }
 
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index 52f3631..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;
     }
 
@@ -475,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()) {
@@ -545,25 +545,25 @@
     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);
         }
 
@@ -572,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;
             }
         }
@@ -589,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);
@@ -662,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/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/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/gnss/aidl/default/Android.bp b/gnss/aidl/default/Android.bp
index 4543665..c8ae6b2 100644
--- a/gnss/aidl/default/Android.bp
+++ b/gnss/aidl/default/Android.bp
@@ -31,7 +31,6 @@
     ],
     vintf_fragments: [
         "gnss-default.xml",
-        "gnss@2.1-service.xml",
     ],
     vendor: true,
     cflags: [
@@ -47,7 +46,6 @@
         "liblog",
         "android.hardware.gnss@2.1",
         "android.hardware.gnss@2.0",
-        "android.hardware.gnss@1.1",
         "android.hardware.gnss@1.0",
         "android.hardware.gnss.measurement_corrections@1.1",
         "android.hardware.gnss.measurement_corrections@1.0",
@@ -62,7 +60,6 @@
         "GnssBatching.cpp",
         "GnssDebug.cpp",
         "GnssGeofence.cpp",
-        "GnssHidlHal.cpp",
         "GnssNavigationMessageInterface.cpp",
         "GnssPowerIndication.cpp",
         "GnssPsds.cpp",
diff --git a/gnss/aidl/default/GnssHidlHal.cpp b/gnss/aidl/default/GnssHidlHal.cpp
deleted file mode 100644
index 10b0106..0000000
--- a/gnss/aidl/default/GnssHidlHal.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "GnssHidlHal"
-
-#include "GnssHidlHal.h"
-
-namespace aidl::android::hardware::gnss {
-
-using GnssSvInfo = ::android::hardware::gnss::V2_1::IGnssCallback::GnssSvInfo;
-
-GnssHidlHal::GnssHidlHal(const std::shared_ptr<Gnss>& gnssAidl) : mGnssAidl(gnssAidl) {
-    Gnss* iGnss = mGnssAidl.get();
-    std::shared_ptr<IGnssConfiguration> iGnssConfiguration;
-    auto status = iGnss->getExtensionGnssConfiguration(&iGnssConfiguration);
-    if (!status.isOk()) {
-        ALOGE("Failed to getExtensionGnssConfiguration.");
-    } else {
-        mGnssConfigurationAidl = iGnss->mGnssConfiguration;
-    }
-
-    std::shared_ptr<IGnssPowerIndication> iGnssPowerIndication;
-    status = iGnss->getExtensionGnssPowerIndication(&iGnssPowerIndication);
-    if (!status.isOk()) {
-        ALOGE("Failed to getExtensionGnssPowerIndication.");
-    } else {
-        mGnssPowerIndicationAidl = iGnss->mGnssPowerIndication;
-    }
-};
-
-hidl_vec<GnssSvInfo> GnssHidlHal::filterBlocklistedSatellitesV2_1(
-        hidl_vec<GnssSvInfo> gnssSvInfoList) {
-    if (mGnssConfigurationAidl == nullptr) {
-        ALOGE("Handle to AIDL GnssConfiguration is not available.");
-        return gnssSvInfoList;
-    }
-    for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
-        if (mGnssConfigurationAidl->isBlocklistedV2_1(gnssSvInfoList[i])) {
-            ALOGD("Blocklisted constellation: %d, svid: %d",
-                  (int)gnssSvInfoList[i].v2_0.constellation, gnssSvInfoList[i].v2_0.v1_0.svid);
-            gnssSvInfoList[i].v2_0.v1_0.svFlag &= ~static_cast<uint8_t>(
-                    ::android::hardware::gnss::V1_0::IGnssCallback::GnssSvFlags::USED_IN_FIX);
-        }
-    }
-    return gnssSvInfoList;
-}
-
-void GnssHidlHal::notePowerConsumption() {
-    mGnssPowerIndicationAidl->notePowerConsumption();
-}
-
-}  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssHidlHal.h b/gnss/aidl/default/GnssHidlHal.h
deleted file mode 100644
index 5fb4f97..0000000
--- a/gnss/aidl/default/GnssHidlHal.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "Gnss.h"
-#include "GnssConfiguration.h"
-#include "v2_1/GnssTemplate.h"
-
-namespace aidl::android::hardware::gnss {
-
-class GnssHidlHal : public ::android::hardware::gnss::common::implementation::GnssTemplate<
-                            ::android::hardware::gnss::V2_1::IGnss> {
-  public:
-    GnssHidlHal(const std::shared_ptr<Gnss>& gnssAidl);
-
-  private:
-    hidl_vec<::android::hardware::gnss::V2_1::IGnssCallback::GnssSvInfo>
-    filterBlocklistedSatellitesV2_1(
-            hidl_vec<::android::hardware::gnss::V2_1::IGnssCallback::GnssSvInfo> gnssSvInfoList)
-            override;
-    void notePowerConsumption() override;
-
-    std::shared_ptr<Gnss> mGnssAidl;
-    std::shared_ptr<GnssConfiguration> mGnssConfigurationAidl;
-    std::shared_ptr<GnssPowerIndication> mGnssPowerIndicationAidl;
-};
-
-}  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/gnss@2.1-service.xml b/gnss/aidl/default/gnss@2.1-service.xml
deleted file mode 100644
index 12a1fdf..0000000
--- a/gnss/aidl/default/gnss@2.1-service.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<manifest version="1.0" type="device">
-    <hal format="hidl">
-        <name>android.hardware.gnss</name>
-        <transport>hwbinder</transport>
-        <version>2.1</version>
-        <version>1.1</version>
-        <interface>
-            <name>IGnss</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-</manifest>
diff --git a/gnss/aidl/default/service.cpp b/gnss/aidl/default/service.cpp
index bbe34f1..162532b 100644
--- a/gnss/aidl/default/service.cpp
+++ b/gnss/aidl/default/service.cpp
@@ -24,15 +24,12 @@
 #include <log/log.h>
 #include <pthread.h>
 #include "Gnss.h"
-#include "GnssHidlHal.h"
 
 using aidl::android::hardware::gnss::Gnss;
-using aidl::android::hardware::gnss::GnssHidlHal;
 using ::android::OK;
 using ::android::sp;
 using ::android::hardware::configureRpcThreadpool;
 using ::android::hardware::joinRpcThreadpool;
-using ::android::hardware::gnss::V2_1::IGnss;
 
 int main() {
     ABinderProcess_setThreadPoolMaxThreadCount(1);
@@ -44,14 +41,6 @@
             AServiceManager_addService(gnssAidl->asBinder().get(), instance.c_str());
     CHECK_EQ(status, STATUS_OK);
 
-    sp<IGnss> gnss = new GnssHidlHal(gnssAidl);
-    configureRpcThreadpool(1, true /* will join */);
-    if (gnss->registerAsService() != OK) {
-        ALOGE("Could not register gnss 2.1 service.");
-        return 0;
-    }
-
-    joinRpcThreadpool();
     ABinderProcess_joinThreadPool();
 
     return EXIT_FAILURE;  // should not reach
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index f75af85..147a9ee 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -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/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/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
index d0ad433..5c3576e 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
@@ -443,6 +443,98 @@
         AuthorizationSetBuilder().Digest(digest).Authorization(TAG_MAC_LENGTH, mac_length));
 }
 
+void KeymasterHidlTest::CheckAesIncrementalEncryptOperation(BlockMode block_mode,
+                                                            int message_size) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .BlockMode(block_mode)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    for (int increment = 1; increment <= message_size; ++increment) {
+        string message(message_size, 'a');
+        auto params = AuthorizationSetBuilder()
+                              .BlockMode(block_mode)
+                              .Padding(PaddingMode::NONE)
+                              .Authorization(TAG_MAC_LENGTH, 128) /* for GCM */;
+
+        AuthorizationSet output_params;
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
+
+        string ciphertext;
+        size_t input_consumed;
+        string to_send;
+        for (size_t i = 0; i < message.size(); i += increment) {
+            to_send.append(message.substr(i, increment));
+            EXPECT_EQ(ErrorCode::OK, Update(to_send, &ciphertext, &input_consumed));
+            EXPECT_EQ(to_send.length(), input_consumed);
+            to_send = to_send.substr(input_consumed);
+            EXPECT_EQ(0U, to_send.length());
+
+            switch (block_mode) {
+                case BlockMode::ECB:
+                case BlockMode::CBC:
+                    // Implementations must take as many blocks as possible, leaving less than
+                    // a block.
+                    EXPECT_LE(to_send.length(), 16U);
+                    break;
+                case BlockMode::GCM:
+                case BlockMode::CTR:
+                    // Implementations must always take all the data.
+                    EXPECT_EQ(0U, to_send.length());
+                    break;
+            }
+        }
+        EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext)) << "Error sending " << to_send;
+
+        switch (block_mode) {
+            case BlockMode::GCM:
+                EXPECT_EQ(message.size() + 16, ciphertext.size());
+                break;
+            case BlockMode::CTR:
+                EXPECT_EQ(message.size(), ciphertext.size());
+                break;
+            case BlockMode::CBC:
+            case BlockMode::ECB:
+                EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size());
+                break;
+        }
+
+        auto iv = output_params.GetTagValue(TAG_NONCE);
+        switch (block_mode) {
+            case BlockMode::CBC:
+            case BlockMode::GCM:
+            case BlockMode::CTR:
+                ASSERT_TRUE(iv.isOk()) << "No IV for block mode " << block_mode;
+                EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv.value().size());
+                params.push_back(TAG_NONCE, iv.value());
+                break;
+
+            case BlockMode::ECB:
+                EXPECT_FALSE(iv.isOk()) << "ECB mode should not generate IV";
+                break;
+        }
+
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params))
+                << "Decrypt begin() failed for block mode " << block_mode;
+
+        string plaintext;
+        for (size_t i = 0; i < ciphertext.size(); i += increment) {
+            to_send.append(ciphertext.substr(i, increment));
+            EXPECT_EQ(ErrorCode::OK, Update(to_send, &plaintext, &input_consumed));
+            to_send = to_send.substr(input_consumed);
+        }
+        ErrorCode error = Finish(to_send, &plaintext);
+        ASSERT_EQ(ErrorCode::OK, error) << "Decryption failed for block mode " << block_mode
+                                        << " and increment " << increment;
+        if (error == ErrorCode::OK) {
+            ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode " << block_mode
+                                          << " and increment " << increment;
+        }
+    }
+}
+
 void KeymasterHidlTest::CheckHmacTestVector(const string& key, const string& message, Digest digest,
                                             const string& expected_mac) {
     SCOPED_TRACE("CheckHmacTestVector");
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
index 2ca7ea7..ad30aa7 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
@@ -166,6 +166,8 @@
 
     string MacMessage(const string& message, Digest digest, size_t mac_length);
 
+    void CheckAesIncrementalEncryptOperation(BlockMode block_mode, int message_size);
+
     void CheckHmacTestVector(const string& key, const string& message, Digest digest,
                              const string& expected_mac);
 
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 6412f3a..22aa0f9 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -2932,105 +2932,39 @@
 }
 
 /*
- * EncryptionOperationsTest.AesIncremental
+ * EncryptionOperationsTest.AesEcbIncremental
  *
- * Verifies that AES works, all modes, when provided data in various size increments.
+ * Verifies that AES works for ECB block mode, when provided data in various size increments.
  */
-TEST_P(EncryptionOperationsTest, AesIncremental) {
-    auto block_modes = {
-        BlockMode::ECB, BlockMode::CBC, BlockMode::CTR, BlockMode::GCM,
-    };
+TEST_P(EncryptionOperationsTest, AesEcbIncremental) {
+    CheckAesIncrementalEncryptOperation(BlockMode::ECB, 240);
+}
 
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                             .Authorization(TAG_NO_AUTH_REQUIRED)
-                                             .AesEncryptionKey(128)
-                                             .BlockMode(block_modes)
-                                             .Padding(PaddingMode::NONE)
-                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+/*
+ * EncryptionOperationsTest.AesCbcIncremental
+ *
+ * Verifies that AES works for CBC block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesCbcIncremental) {
+    CheckAesIncrementalEncryptOperation(BlockMode::CBC, 240);
+}
 
-    for (int increment = 1; increment <= 240; ++increment) {
-        for (auto block_mode : block_modes) {
-            string message(240, 'a');
-            auto params = AuthorizationSetBuilder()
-                              .BlockMode(block_mode)
-                              .Padding(PaddingMode::NONE)
-                              .Authorization(TAG_MAC_LENGTH, 128) /* for GCM */;
+/*
+ * EncryptionOperationsTest.AesCtrIncremental
+ *
+ * Verifies that AES works for CTR block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesCtrIncremental) {
+    CheckAesIncrementalEncryptOperation(BlockMode::CTR, 240);
+}
 
-            AuthorizationSet output_params;
-            EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
-
-            string ciphertext;
-            size_t input_consumed;
-            string to_send;
-            for (size_t i = 0; i < message.size(); i += increment) {
-                to_send.append(message.substr(i, increment));
-                EXPECT_EQ(ErrorCode::OK, Update(to_send, &ciphertext, &input_consumed));
-                EXPECT_EQ(to_send.length(), input_consumed);
-                to_send = to_send.substr(input_consumed);
-                EXPECT_EQ(0U, to_send.length());
-
-                switch (block_mode) {
-                    case BlockMode::ECB:
-                    case BlockMode::CBC:
-                        // Implementations must take as many blocks as possible, leaving less than
-                        // a block.
-                        EXPECT_LE(to_send.length(), 16U);
-                        break;
-                    case BlockMode::GCM:
-                    case BlockMode::CTR:
-                        // Implementations must always take all the data.
-                        EXPECT_EQ(0U, to_send.length());
-                        break;
-                }
-            }
-            EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext)) << "Error sending " << to_send;
-
-            switch (block_mode) {
-                case BlockMode::GCM:
-                    EXPECT_EQ(message.size() + 16, ciphertext.size());
-                    break;
-                case BlockMode::CTR:
-                    EXPECT_EQ(message.size(), ciphertext.size());
-                    break;
-                case BlockMode::CBC:
-                case BlockMode::ECB:
-                    EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size());
-                    break;
-            }
-
-            auto iv = output_params.GetTagValue(TAG_NONCE);
-            switch (block_mode) {
-                case BlockMode::CBC:
-                case BlockMode::GCM:
-                case BlockMode::CTR:
-                    ASSERT_TRUE(iv.isOk()) << "No IV for block mode " << block_mode;
-                    EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv.value().size());
-                    params.push_back(TAG_NONCE, iv.value());
-                    break;
-
-                case BlockMode::ECB:
-                    EXPECT_FALSE(iv.isOk()) << "ECB mode should not generate IV";
-                    break;
-            }
-
-            EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params))
-                << "Decrypt begin() failed for block mode " << block_mode;
-
-            string plaintext;
-            for (size_t i = 0; i < ciphertext.size(); i += increment) {
-                to_send.append(ciphertext.substr(i, increment));
-                EXPECT_EQ(ErrorCode::OK, Update(to_send, &plaintext, &input_consumed));
-                to_send = to_send.substr(input_consumed);
-            }
-            ErrorCode error = Finish(to_send, &plaintext);
-            ASSERT_EQ(ErrorCode::OK, error) << "Decryption failed for block mode " << block_mode
-                                            << " and increment " << increment;
-            if (error == ErrorCode::OK) {
-                ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode "
-                                              << block_mode << " and increment " << increment;
-            }
-        }
-    }
+/*
+ * EncryptionOperationsTest.AesGcmIncremental
+ *
+ * Verifies that AES works for GCM block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmIncremental) {
+    CheckAesIncrementalEncryptOperation(BlockMode::GCM, 240);
 }
 
 struct AesCtrSp80038aTestVector {
diff --git a/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/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/utils/adapter/aidl/include/nnapi/hal/aidl/Adapter.h b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Adapter.h
index 4c0b328..80ed41d 100644
--- a/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Adapter.h
+++ b/neuralnetworks/utils/adapter/aidl/include/nnapi/hal/aidl/Adapter.h
@@ -46,9 +46,6 @@
 /**
  * Adapt an NNAPI canonical interface object to a AIDL NN HAL interface object.
  *
- * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
- * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
- *
  * @param device NNAPI canonical IDevice interface object to be adapted.
  * @param executor Type-erased executor to handle executing tasks asynchronously.
  * @return AIDL NN HAL IDevice interface object.
@@ -58,9 +55,6 @@
 /**
  * Adapt an NNAPI canonical interface object to a AIDL NN HAL interface object.
  *
- * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
- * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
- *
  * This function uses a default executor, which will execute tasks from a detached thread.
  *
  * @param device NNAPI canonical IDevice interface object to be adapted.
diff --git a/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Adapter.h b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Adapter.h
index 6fba4ab..3bd93e0 100644
--- a/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Adapter.h
+++ b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/Adapter.h
@@ -46,9 +46,6 @@
 /**
  * Adapt an NNAPI canonical interface object to a HIDL NN HAL interface object.
  *
- * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
- * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
- *
  * @param device NNAPI canonical IDevice interface object to be adapted.
  * @param executor Type-erased executor to handle executing tasks asynchronously.
  * @return HIDL NN HAL IDevice interface object.
@@ -58,9 +55,6 @@
 /**
  * Adapt an NNAPI canonical interface object to a HIDL NN HAL interface object.
  *
- * The IPreparedModel object created from IDevice::prepareModel or IDevice::preparedModelFromCache
- * must return "const nn::Model*" from IPreparedModel::getUnderlyingResource().
- *
  * This function uses a default executor, which will execute tasks from a detached thread.
  *
  * @param device NNAPI canonical IDevice interface object to be adapted.
diff --git a/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/PreparedModel.h b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/PreparedModel.h
index 9482b0d..01cd4bc 100644
--- a/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/PreparedModel.h
+++ b/neuralnetworks/utils/adapter/hidl/include/nnapi/hal/PreparedModel.h
@@ -39,7 +39,7 @@
 // Class that adapts nn::IPreparedModel to V1_3::IPreparedModel.
 class PreparedModel final : public V1_3::IPreparedModel {
   public:
-    PreparedModel(nn::SharedPreparedModel preparedModel, Executor executor);
+    explicit PreparedModel(nn::SharedPreparedModel preparedModel);
 
     Return<V1_0::ErrorStatus> execute(const V1_0::Request& request,
                                       const sp<V1_0::IExecutionCallback>& callback) override;
@@ -70,7 +70,6 @@
 
   private:
     const nn::SharedPreparedModel kPreparedModel;
-    const Executor kExecutor;
 };
 
 }  // namespace android::hardware::neuralnetworks::adapter
diff --git a/neuralnetworks/utils/adapter/hidl/src/Device.cpp b/neuralnetworks/utils/adapter/hidl/src/Device.cpp
index 0f44638..305a1b4 100644
--- a/neuralnetworks/utils/adapter/hidl/src/Device.cpp
+++ b/neuralnetworks/utils/adapter/hidl/src/Device.cpp
@@ -62,11 +62,11 @@
 
 using PrepareModelResult = nn::GeneralResult<nn::SharedPreparedModel>;
 
-sp<PreparedModel> adaptPreparedModel(nn::SharedPreparedModel preparedModel, Executor executor) {
+sp<PreparedModel> adaptPreparedModel(nn::SharedPreparedModel preparedModel) {
     if (preparedModel == nullptr) {
         return nullptr;
     }
-    return sp<PreparedModel>::make(std::move(preparedModel), std::move(executor));
+    return sp<PreparedModel>::make(std::move(preparedModel));
 }
 
 void notify(V1_0::IPreparedModelCallback* callback, nn::ErrorStatus status,
@@ -105,14 +105,14 @@
 }
 
 template <typename CallbackType>
-void notify(CallbackType* callback, PrepareModelResult result, Executor executor) {
+void notify(CallbackType* callback, PrepareModelResult result) {
     if (!result.has_value()) {
         const auto [message, status] = std::move(result).error();
         LOG(ERROR) << message;
         notify(callback, status, nullptr);
     } else {
         auto preparedModel = std::move(result).value();
-        auto hidlPreparedModel = adaptPreparedModel(std::move(preparedModel), std::move(executor));
+        auto hidlPreparedModel = adaptPreparedModel(std::move(preparedModel));
         notify(callback, nn::ErrorStatus::NONE, std::move(hidlPreparedModel));
     }
 }
@@ -133,10 +133,10 @@
 
     auto nnModel = NN_TRY(convertInput(model));
 
-    Task task = [device, nnModel = std::move(nnModel), executor, callback] {
+    Task task = [device, nnModel = std::move(nnModel), callback] {
         auto result = device->prepareModel(nnModel, nn::ExecutionPreference::DEFAULT,
                                            nn::Priority::DEFAULT, {}, {}, {}, {}, {}, {});
-        notify(callback.get(), std::move(result), executor);
+        notify(callback.get(), std::move(result));
     };
     executor(std::move(task), {});
 
@@ -154,10 +154,10 @@
     auto nnModel = NN_TRY(convertInput(model));
     const auto nnPreference = NN_TRY(convertInput(preference));
 
-    Task task = [device, nnModel = std::move(nnModel), nnPreference, executor, callback] {
+    Task task = [device, nnModel = std::move(nnModel), nnPreference, callback] {
         auto result = device->prepareModel(nnModel, nnPreference, nn::Priority::DEFAULT, {}, {}, {},
                                            {}, {}, {});
-        notify(callback.get(), std::move(result), executor);
+        notify(callback.get(), std::move(result));
     };
     executor(std::move(task), {});
 
@@ -183,10 +183,10 @@
 
     Task task = [device, nnModel = std::move(nnModel), nnPreference,
                  nnModelCache = std::move(nnModelCache), nnDataCache = std::move(nnDataCache),
-                 nnToken, executor, callback] {
+                 nnToken, callback] {
         auto result = device->prepareModel(nnModel, nnPreference, nn::Priority::DEFAULT, {},
                                            nnModelCache, nnDataCache, nnToken, {}, {});
-        notify(callback.get(), std::move(result), executor);
+        notify(callback.get(), std::move(result));
     };
     executor(std::move(task), {});
 
@@ -213,10 +213,10 @@
 
     Task task = [device, nnModel = std::move(nnModel), nnPreference, nnPriority, nnDeadline,
                  nnModelCache = std::move(nnModelCache), nnDataCache = std::move(nnDataCache),
-                 nnToken, executor, callback] {
+                 nnToken, callback] {
         auto result = device->prepareModel(nnModel, nnPreference, nnPriority, nnDeadline,
                                            nnModelCache, nnDataCache, nnToken, {}, {});
-        notify(callback.get(), std::move(result), executor);
+        notify(callback.get(), std::move(result));
     };
     executor(std::move(task), nnDeadline);
 
@@ -238,9 +238,9 @@
     const auto nnToken = nn::CacheToken(token);
 
     Task task = [device, nnModelCache = std::move(nnModelCache),
-                 nnDataCache = std::move(nnDataCache), nnToken, executor, callback] {
+                 nnDataCache = std::move(nnDataCache), nnToken, callback] {
         auto result = device->prepareModelFromCache({}, nnModelCache, nnDataCache, nnToken);
-        notify(callback.get(), std::move(result), executor);
+        notify(callback.get(), std::move(result));
     };
     executor(std::move(task), {});
 
@@ -262,9 +262,9 @@
     const auto nnToken = nn::CacheToken(token);
 
     auto task = [device, nnDeadline, nnModelCache = std::move(nnModelCache),
-                 nnDataCache = std::move(nnDataCache), nnToken, executor, callback] {
+                 nnDataCache = std::move(nnDataCache), nnToken, callback] {
         auto result = device->prepareModelFromCache(nnDeadline, nnModelCache, nnDataCache, nnToken);
-        notify(callback.get(), std::move(result), executor);
+        notify(callback.get(), std::move(result));
     };
     executor(std::move(task), nnDeadline);
 
diff --git a/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp b/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp
index c6055a6..3570a74 100644
--- a/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp
+++ b/neuralnetworks/utils/adapter/hidl/src/PreparedModel.cpp
@@ -55,15 +55,6 @@
     return result;
 }
 
-nn::GeneralResult<nn::Version> validateRequestForModel(const nn::Request& request,
-                                                       const nn::Model& model) {
-    nn::GeneralResult<nn::Version> version = nn::validateRequestForModel(request, model);
-    if (!version.ok()) {
-        version.error().code = nn::ErrorStatus::INVALID_ARGUMENT;
-    }
-    return version;
-}
-
 class FencedExecutionCallback final : public V1_3::IFencedExecutionCallback {
   public:
     explicit FencedExecutionCallback(const nn::ExecuteFencedInfoCallback& callback)
@@ -144,58 +135,48 @@
 }
 
 nn::GeneralResult<void> execute(const nn::SharedPreparedModel& preparedModel,
-                                const Executor& executor, const V1_0::Request& request,
+                                const V1_0::Request& request,
                                 const sp<V1_0::IExecutionCallback>& callback) {
     if (callback.get() == nullptr) {
         return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
     }
 
-    auto nnRequest = NN_TRY(convertInput(request));
+    const auto nnRequest = NN_TRY(convertInput(request));
 
-    const std::any resource = preparedModel->getUnderlyingResource();
-    if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
-        CHECK(*model != nullptr);
-        NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
+    auto result = preparedModel->execute(nnRequest, nn::MeasureTiming::NO, {}, {}, {}, {});
+
+    if (!result.ok() && result.error().code == nn::ErrorStatus::INVALID_ARGUMENT) {
+        const auto& [message, code, outputShapes] = result.error();
+        return nn::error(code) << message;
     }
 
-    Task task = [preparedModel, nnRequest = std::move(nnRequest), callback] {
-        auto result = preparedModel->execute(nnRequest, nn::MeasureTiming::NO, {}, {}, {}, {});
-        notify(callback.get(), std::move(result));
-    };
-    executor(std::move(task), {});
-
+    notify(callback.get(), std::move(result));
     return {};
 }
 
 nn::GeneralResult<void> execute_1_2(const nn::SharedPreparedModel& preparedModel,
-                                    const Executor& executor, const V1_0::Request& request,
-                                    V1_2::MeasureTiming measure,
+                                    const V1_0::Request& request, V1_2::MeasureTiming measure,
                                     const sp<V1_2::IExecutionCallback>& callback) {
     if (callback.get() == nullptr) {
         return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
     }
 
-    auto nnRequest = NN_TRY(convertInput(request));
+    const auto nnRequest = NN_TRY(convertInput(request));
     const auto nnMeasure = NN_TRY(convertInput(measure));
 
-    const std::any resource = preparedModel->getUnderlyingResource();
-    if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
-        CHECK(*model != nullptr);
-        NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
+    auto result = preparedModel->execute(nnRequest, nnMeasure, {}, {}, {}, {});
+
+    if (!result.ok() && result.error().code == nn::ErrorStatus::INVALID_ARGUMENT) {
+        const auto& [message, code, outputShapes] = result.error();
+        return nn::error(code) << message;
     }
 
-    Task task = [preparedModel, nnRequest = std::move(nnRequest), nnMeasure, callback] {
-        auto result = preparedModel->execute(nnRequest, nnMeasure, {}, {}, {}, {});
-        notify(callback.get(), std::move(result));
-    };
-    executor(std::move(task), {});
-
+    notify(callback.get(), std::move(result));
     return {};
 }
 
 nn::GeneralResult<void> execute_1_3(const nn::SharedPreparedModel& preparedModel,
-                                    const Executor& executor, const V1_3::Request& request,
-                                    V1_2::MeasureTiming measure,
+                                    const V1_3::Request& request, V1_2::MeasureTiming measure,
                                     const V1_3::OptionalTimePoint& deadline,
                                     const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
                                     const sp<V1_3::IExecutionCallback>& callback) {
@@ -203,25 +184,20 @@
         return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
     }
 
-    auto nnRequest = NN_TRY(convertInput(request));
+    const auto nnRequest = NN_TRY(convertInput(request));
     const auto nnMeasure = NN_TRY(convertInput(measure));
     const auto nnDeadline = NN_TRY(convertInput(deadline));
     const auto nnLoopTimeoutDuration = NN_TRY(convertInput(loopTimeoutDuration));
 
-    const std::any resource = preparedModel->getUnderlyingResource();
-    if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
-        CHECK(*model != nullptr);
-        NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
+    auto result =
+            preparedModel->execute(nnRequest, nnMeasure, nnDeadline, nnLoopTimeoutDuration, {}, {});
+
+    if (!result.ok() && result.error().code == nn::ErrorStatus::INVALID_ARGUMENT) {
+        const auto& [message, code, outputShapes] = result.error();
+        return nn::error(code) << message;
     }
 
-    Task task = [preparedModel, nnRequest = std::move(nnRequest), nnMeasure, nnDeadline,
-                 nnLoopTimeoutDuration, callback] {
-        auto result = preparedModel->execute(nnRequest, nnMeasure, nnDeadline,
-                                             nnLoopTimeoutDuration, {}, {});
-        notify(callback.get(), std::move(result));
-    };
-    executor(std::move(task), nnDeadline);
-
+    notify(callback.get(), std::move(result));
     return {};
 }
 
@@ -304,10 +280,9 @@
 
 }  // namespace
 
-PreparedModel::PreparedModel(nn::SharedPreparedModel preparedModel, Executor executor)
-    : kPreparedModel(std::move(preparedModel)), kExecutor(std::move(executor)) {
+PreparedModel::PreparedModel(nn::SharedPreparedModel preparedModel)
+    : kPreparedModel(std::move(preparedModel)) {
     CHECK(kPreparedModel != nullptr);
-    CHECK(kExecutor != nullptr);
 }
 
 nn::SharedPreparedModel PreparedModel::getUnderlyingPreparedModel() const {
@@ -316,7 +291,7 @@
 
 Return<V1_0::ErrorStatus> PreparedModel::execute(const V1_0::Request& request,
                                                  const sp<V1_0::IExecutionCallback>& callback) {
-    auto result = adapter::execute(kPreparedModel, kExecutor, request, callback);
+    auto result = adapter::execute(kPreparedModel, request, callback);
     if (!result.has_value()) {
         auto [message, code] = std::move(result).error();
         LOG(ERROR) << "adapter::PreparedModel::execute failed with " << code << ": " << message;
@@ -329,7 +304,7 @@
 Return<V1_0::ErrorStatus> PreparedModel::execute_1_2(const V1_0::Request& request,
                                                      V1_2::MeasureTiming measure,
                                                      const sp<V1_2::IExecutionCallback>& callback) {
-    auto result = adapter::execute_1_2(kPreparedModel, kExecutor, request, measure, callback);
+    auto result = adapter::execute_1_2(kPreparedModel, request, measure, callback);
     if (!result.has_value()) {
         auto [message, code] = std::move(result).error();
         LOG(ERROR) << "adapter::PreparedModel::execute_1_2 failed with " << code << ": " << message;
@@ -344,7 +319,7 @@
         const V1_3::OptionalTimePoint& deadline,
         const V1_3::OptionalTimeoutDuration& loopTimeoutDuration,
         const sp<V1_3::IExecutionCallback>& callback) {
-    auto result = adapter::execute_1_3(kPreparedModel, kExecutor, request, measure, deadline,
+    auto result = adapter::execute_1_3(kPreparedModel, request, measure, deadline,
                                        loopTimeoutDuration, callback);
     if (!result.has_value()) {
         auto [message, code] = std::move(result).error();
@@ -405,8 +380,8 @@
         cb(V1_2::utils::convert(code).value(), nullptr);
         return Void();
     }
-    auto burstContext = std::move(result).value();
-    cb(V1_0::ErrorStatus::NONE, std::move(burstContext));
+    const auto burstContext = std::move(result).value();
+    cb(V1_0::ErrorStatus::NONE, burstContext);
     return Void();
 }
 
diff --git a/radio/aidl/android/hardware/radio/data/IRadioData.aidl b/radio/aidl/android/hardware/radio/data/IRadioData.aidl
index e1ba568..0171d39 100644
--- a/radio/aidl/android/hardware/radio/data/IRadioData.aidl
+++ b/radio/aidl/android/hardware/radio/data/IRadioData.aidl
@@ -65,6 +65,7 @@
     /**
      * Deactivate packet data connection and remove from the data call list. An
      * unsolDataCallListChanged() must be sent when data connection is deactivated.
+     * Any return value other than RadioError::NONE will remove the network from the list.
      *
      * @param serial Serial number of request.
      * @param cid Data call id.
@@ -76,8 +77,7 @@
 
     /**
      * Returns the data call list. An entry is added when a setupDataCall() is issued and removed
-     * on a deactivateDataCall(). The list is emptied when setRadioPower()  off/on issued or when
-     * the vendor HAL or modem crashes.
+     * on a deactivateDataCall(). The list is emptied when the vendor HAL crashes.
      *
      * @param serial Serial number of request.
      *
diff --git a/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl b/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl
index bbc8d07..88b6c1b 100644
--- a/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl
+++ b/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl
@@ -67,7 +67,7 @@
      *
      * Valid errors returned:
      *   RadioError:REQUEST_NOT_SUPPORTED may be returned when HAL 1.2 or higher is supported.
-     *   RadioError:NONE
+     *   RadioError:NONE indicates success. Any other error will remove the network from the list.
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_CALL_ID
      *   RadioError:INVALID_STATE
diff --git a/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/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index ff4036c..c17a0b8 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -665,6 +665,78 @@
             AuthorizationSetBuilder().Digest(digest).Authorization(TAG_MAC_LENGTH, mac_length));
 }
 
+void KeyMintAidlTestBase::CheckAesIncrementalEncryptOperation(BlockMode block_mode,
+                                                              int message_size) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .BlockMode(block_mode)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    for (int increment = 1; increment <= message_size; ++increment) {
+        string message(message_size, 'a');
+        auto params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(PaddingMode::NONE);
+        if (block_mode == BlockMode::GCM) {
+            params.Authorization(TAG_MAC_LENGTH, 128) /* for GCM */;
+        }
+
+        AuthorizationSet output_params;
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
+
+        string ciphertext;
+        string to_send;
+        for (size_t i = 0; i < message.size(); i += increment) {
+            EXPECT_EQ(ErrorCode::OK, Update(message.substr(i, increment), &ciphertext));
+        }
+        EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext))
+                << "Error sending " << to_send << " with block mode " << block_mode;
+
+        switch (block_mode) {
+            case BlockMode::GCM:
+                EXPECT_EQ(message.size() + 16, ciphertext.size());
+                break;
+            case BlockMode::CTR:
+                EXPECT_EQ(message.size(), ciphertext.size());
+                break;
+            case BlockMode::CBC:
+            case BlockMode::ECB:
+                EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size());
+                break;
+        }
+
+        auto iv = output_params.GetTagValue(TAG_NONCE);
+        switch (block_mode) {
+            case BlockMode::CBC:
+            case BlockMode::GCM:
+            case BlockMode::CTR:
+                ASSERT_TRUE(iv) << "No IV for block mode " << block_mode;
+                EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv->get().size());
+                params.push_back(TAG_NONCE, iv->get());
+                break;
+
+            case BlockMode::ECB:
+                EXPECT_FALSE(iv) << "ECB mode should not generate IV";
+                break;
+        }
+
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params))
+                << "Decrypt begin() failed for block mode " << block_mode;
+
+        string plaintext;
+        for (size_t i = 0; i < ciphertext.size(); i += increment) {
+            EXPECT_EQ(ErrorCode::OK, Update(ciphertext.substr(i, increment), &plaintext));
+        }
+        ErrorCode error = Finish(to_send, &plaintext);
+        ASSERT_EQ(ErrorCode::OK, error) << "Decryption failed for block mode " << block_mode
+                                        << " and increment " << increment;
+        if (error == ErrorCode::OK) {
+            ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode " << block_mode
+                                          << " and increment " << increment;
+        }
+    }
+}
+
 void KeyMintAidlTestBase::CheckHmacTestVector(const string& key, const string& message,
                                               Digest digest, const string& expected_mac) {
     SCOPED_TRACE("CheckHmacTestVector");
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 6fb5bf5..e59443c 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -169,6 +169,8 @@
 
     string MacMessage(const string& message, Digest digest, size_t mac_length);
 
+    void CheckAesIncrementalEncryptOperation(BlockMode block_mode, int message_size);
+
     void CheckHmacTestVector(const string& key, const string& message, Digest digest,
                              const string& expected_mac);
 
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 38abe81..056d83a 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -5441,89 +5441,39 @@
 }
 
 /*
- * EncryptionOperationsTest.AesIncremental
+ * EncryptionOperationsTest.AesEcbIncremental
  *
- * Verifies that AES works, all modes, when provided data in various size increments.
+ * Verifies that AES works for ECB block mode, when provided data in various size increments.
  */
-TEST_P(EncryptionOperationsTest, AesIncremental) {
-    auto block_modes = {
-            BlockMode::ECB,
-            BlockMode::CBC,
-            BlockMode::CTR,
-            BlockMode::GCM,
-    };
+TEST_P(EncryptionOperationsTest, AesEcbIncremental) {
+    CheckAesIncrementalEncryptOperation(BlockMode::ECB, 240);
+}
 
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
-                                                 .AesEncryptionKey(128)
-                                                 .BlockMode(block_modes)
-                                                 .Padding(PaddingMode::NONE)
-                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+/*
+ * EncryptionOperationsTest.AesCbcIncremental
+ *
+ * Verifies that AES works for CBC block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesCbcIncremental) {
+    CheckAesIncrementalEncryptOperation(BlockMode::CBC, 240);
+}
 
-    for (int increment = 1; increment <= 240; ++increment) {
-        for (auto block_mode : block_modes) {
-            string message(240, 'a');
-            auto params =
-                    AuthorizationSetBuilder().BlockMode(block_mode).Padding(PaddingMode::NONE);
-            if (block_mode == BlockMode::GCM) {
-                params.Authorization(TAG_MAC_LENGTH, 128) /* for GCM */;
-            }
+/*
+ * EncryptionOperationsTest.AesCtrIncremental
+ *
+ * Verifies that AES works for CTR block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesCtrIncremental) {
+    CheckAesIncrementalEncryptOperation(BlockMode::CTR, 240);
+}
 
-            AuthorizationSet output_params;
-            EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
-
-            string ciphertext;
-            string to_send;
-            for (size_t i = 0; i < message.size(); i += increment) {
-                EXPECT_EQ(ErrorCode::OK, Update(message.substr(i, increment), &ciphertext));
-            }
-            EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext))
-                    << "Error sending " << to_send << " with block mode " << block_mode;
-
-            switch (block_mode) {
-                case BlockMode::GCM:
-                    EXPECT_EQ(message.size() + 16, ciphertext.size());
-                    break;
-                case BlockMode::CTR:
-                    EXPECT_EQ(message.size(), ciphertext.size());
-                    break;
-                case BlockMode::CBC:
-                case BlockMode::ECB:
-                    EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size());
-                    break;
-            }
-
-            auto iv = output_params.GetTagValue(TAG_NONCE);
-            switch (block_mode) {
-                case BlockMode::CBC:
-                case BlockMode::GCM:
-                case BlockMode::CTR:
-                    ASSERT_TRUE(iv) << "No IV for block mode " << block_mode;
-                    EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv->get().size());
-                    params.push_back(TAG_NONCE, iv->get());
-                    break;
-
-                case BlockMode::ECB:
-                    EXPECT_FALSE(iv) << "ECB mode should not generate IV";
-                    break;
-            }
-
-            EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params))
-                    << "Decrypt begin() failed for block mode " << block_mode;
-
-            string plaintext;
-            for (size_t i = 0; i < ciphertext.size(); i += increment) {
-                EXPECT_EQ(ErrorCode::OK, Update(ciphertext.substr(i, increment), &plaintext));
-            }
-            ErrorCode error = Finish(to_send, &plaintext);
-            ASSERT_EQ(ErrorCode::OK, error) << "Decryption failed for block mode " << block_mode
-                                            << " and increment " << increment;
-            if (error == ErrorCode::OK) {
-                ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode "
-                                              << block_mode << " and increment " << increment;
-            }
-        }
-    }
+/*
+ * EncryptionOperationsTest.AesGcmIncremental
+ *
+ * Verifies that AES works for GCM block mode, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmIncremental) {
+    CheckAesIncrementalEncryptOperation(BlockMode::GCM, 240);
 }
 
 struct AesCtrSp80038aTestVector {
diff --git a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
index e16a47b..83ee188 100644
--- a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
+++ b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
@@ -38,7 +38,7 @@
 
 class SecureElementProvisioningTest : public testing::Test {
   protected:
-    static void SetupTestSuite() {
+    static void SetUpTestSuite() {
         auto params = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
         for (auto& param : params) {
             ASSERT_TRUE(AServiceManager_isDeclared(param.c_str()))
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/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/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.6/vts/functional/wifi_chip_hidl_test.cpp
index d1d4336..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,9 @@
     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);
 }
@@ -104,6 +107,22 @@
     EXPECT_LT(0u, status_and_modes.second.size());
 }
 
+/*
+ * getSupportedRadioCombinationsMatrix:
+ * Ensure that a call to getSupportedRadioCombinationsMatrix will return
+ * with a success status code.
+ */
+TEST_P(WifiChipHidlTest, getSupportedRadioCombinationsMatrix) {
+    configureChipForIfaceType(IfaceType::STA, true);
+    const auto& statusNonEmpty = HIDL_INVOKE(wifi_chip_, getSupportedRadioCombinationsMatrix);
+    if (statusNonEmpty.first.code == WifiStatusCode::ERROR_NOT_SUPPORTED) {
+        GTEST_SKIP() << "Skipping this test since getSupportedRadioCombinationsMatrix() is not "
+                        "supported by vendor.";
+    }
+
+    EXPECT_EQ(WifiStatusCode::SUCCESS, statusNonEmpty.first.code);
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlTest);
 INSTANTIATE_TEST_SUITE_P(PerInstance, WifiChipHidlTest,
                          testing::ValuesIn(android::hardware::getAllHalInstanceNames(
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(