Merge changes from topic "nnapi-numberOfConsumers"

* changes:
  Create NNAPI adapter interface
  Make NNAPI countNumberOfConsumers return GeneralResult -- hal
diff --git a/biometrics/face/1.1/default/Android.bp b/biometrics/face/1.0/default/Android.bp
similarity index 84%
rename from biometrics/face/1.1/default/Android.bp
rename to biometrics/face/1.0/default/Android.bp
index 360071f..d6ff087 100644
--- a/biometrics/face/1.1/default/Android.bp
+++ b/biometrics/face/1.0/default/Android.bp
@@ -15,10 +15,10 @@
  */
 
 cc_binary {
-    name: "android.hardware.biometrics.face@1.1-service.example",
+    name: "android.hardware.biometrics.face@1.0-service.example",
     defaults: ["hidl_defaults"],
     vendor: true,
-    init_rc: ["android.hardware.biometrics.face@1.1-service.rc"],
+    init_rc: ["android.hardware.biometrics.face@1.0-service.rc"],
     vintf_fragments: ["manifest_face_default.xml"],
     relative_install_path: "hw",
     proprietary: true,
@@ -31,6 +31,5 @@
         "libutils",
         "liblog",
         "android.hardware.biometrics.face@1.0",
-        "android.hardware.biometrics.face@1.1",
     ],
 }
diff --git a/biometrics/face/1.1/default/BiometricsFace.cpp b/biometrics/face/1.0/default/BiometricsFace.cpp
similarity index 81%
rename from biometrics/face/1.1/default/BiometricsFace.cpp
rename to biometrics/face/1.0/default/BiometricsFace.cpp
index 57b3a92..97dc469 100644
--- a/biometrics/face/1.1/default/BiometricsFace.cpp
+++ b/biometrics/face/1.0/default/BiometricsFace.cpp
@@ -110,20 +110,4 @@
     return Status::OK;
 }
 
-// Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow.
-Return<Status> BiometricsFace::enroll_1_1(const hidl_vec<uint8_t>& /* hat */,
-                                          uint32_t /* timeoutSec */,
-                                          const hidl_vec<Feature>& /* disabledFeatures */,
-                                          const hidl_handle& /* windowId */) {
-    mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */);
-    return Status::OK;
-}
-
-Return<Status> BiometricsFace::enrollRemotely(const hidl_vec<uint8_t>& /* hat */,
-                                              uint32_t /* timeoutSec */,
-                                              const hidl_vec<Feature>& /* disabledFeatures */) {
-    mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */);
-    return Status::OK;
-}
-
 }  // namespace android::hardware::biometrics::face::implementation
diff --git a/biometrics/face/1.1/default/BiometricsFace.h b/biometrics/face/1.0/default/BiometricsFace.h
similarity index 81%
rename from biometrics/face/1.1/default/BiometricsFace.h
rename to biometrics/face/1.0/default/BiometricsFace.h
index 5ce5771..1d99ed2 100644
--- a/biometrics/face/1.1/default/BiometricsFace.h
+++ b/biometrics/face/1.0/default/BiometricsFace.h
@@ -16,7 +16,7 @@
 
 #pragma once
 
-#include <android/hardware/biometrics/face/1.1/IBiometricsFace.h>
+#include <android/hardware/biometrics/face/1.0/IBiometricsFace.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 #include <random>
@@ -34,7 +34,7 @@
 using ::android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback;
 using ::android::hardware::biometrics::face::V1_0::Status;
 
-class BiometricsFace : public V1_1::IBiometricsFace {
+class BiometricsFace : public V1_0::IBiometricsFace {
   public:
     BiometricsFace();
 
@@ -71,14 +71,6 @@
 
     Return<Status> resetLockout(const hidl_vec<uint8_t>& hat) override;
 
-    // Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow.
-    Return<Status> enroll_1_1(const hidl_vec<uint8_t>& hat, uint32_t timeoutSec,
-                              const hidl_vec<Feature>& disabledFeatures,
-                              const hidl_handle& windowId) override;
-
-    Return<Status> enrollRemotely(const hidl_vec<uint8_t>& hat, uint32_t timeoutSec,
-                                  const hidl_vec<Feature>& disabledFeatures) override;
-
   private:
     std::mt19937 mRandom;
     int32_t mUserId;
diff --git a/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc b/biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc
similarity index 75%
rename from biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc
rename to biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc
index 687e2d8..6c7362f 100644
--- a/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc
+++ b/biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc
@@ -1,4 +1,4 @@
-service vendor.face-hal-1-1-default /vendor/bin/hw/android.hardware.biometrics.face@1.1-service.example
+service vendor.face-hal-1-0-default /vendor/bin/hw/android.hardware.biometrics.face@1.0-service.example
     # "class hal" causes a race condition on some devices due to files created
     # in /data. As a workaround, postpone startup until later in boot once
     # /data is mounted.
diff --git a/biometrics/face/1.1/default/manifest_face_default.xml b/biometrics/face/1.0/default/manifest_face_default.xml
similarity index 90%
rename from biometrics/face/1.1/default/manifest_face_default.xml
rename to biometrics/face/1.0/default/manifest_face_default.xml
index ec71d9c..380ae49 100644
--- a/biometrics/face/1.1/default/manifest_face_default.xml
+++ b/biometrics/face/1.0/default/manifest_face_default.xml
@@ -2,7 +2,7 @@
     <hal format="hidl">
         <name>android.hardware.biometrics.face</name>
         <transport>hwbinder</transport>
-        <version>1.1</version>
+        <version>1.0</version>
         <interface>
             <name>IBiometricsFace</name>
             <instance>default</instance>
diff --git a/biometrics/face/1.1/default/service.cpp b/biometrics/face/1.0/default/service.cpp
similarity index 88%
rename from biometrics/face/1.1/default/service.cpp
rename to biometrics/face/1.0/default/service.cpp
index 344bdb9..9818c95 100644
--- a/biometrics/face/1.1/default/service.cpp
+++ b/biometrics/face/1.0/default/service.cpp
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "android.hardware.biometrics.face@1.1-service"
+#define LOG_TAG "android.hardware.biometrics.face@1.0-service"
 
 #include <android/hardware/biometrics/face/1.0/types.h>
-#include <android/hardware/biometrics/face/1.1/IBiometricsFace.h>
+#include <android/hardware/biometrics/face/1.0/IBiometricsFace.h>
 #include <android/log.h>
 #include <hidl/HidlSupport.h>
 #include <hidl/HidlTransportSupport.h>
@@ -27,7 +27,7 @@
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
 using android::hardware::biometrics::face::implementation::BiometricsFace;
-using android::hardware::biometrics::face::V1_1::IBiometricsFace;
+using android::hardware::biometrics::face::V1_0::IBiometricsFace;
 
 int main() {
     ALOGI("BiometricsFace HAL is being started.");
diff --git a/biometrics/face/1.1/Android.bp b/biometrics/face/1.1/Android.bp
deleted file mode 100644
index 14a86f1..0000000
--- a/biometrics/face/1.1/Android.bp
+++ /dev/null
@@ -1,14 +0,0 @@
-// This file is autogenerated by hidl-gen -Landroidbp.
-
-hidl_interface {
-    name: "android.hardware.biometrics.face@1.1",
-    root: "android.hardware",
-    srcs: [
-        "IBiometricsFace.hal",
-    ],
-    interfaces: [
-        "android.hardware.biometrics.face@1.0",
-        "android.hidl.base@1.0",
-    ],
-    gen_java: true,
-}
diff --git a/biometrics/face/1.1/IBiometricsFace.hal b/biometrics/face/1.1/IBiometricsFace.hal
deleted file mode 100644
index 84e7443..0000000
--- a/biometrics/face/1.1/IBiometricsFace.hal
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.biometrics.face@1.1;
-
-import @1.0::IBiometricsFace;
-import @1.0::Status;
-import @1.0::Feature;
-
-/**
- * The HAL interface for biometric face authentication.
- */
-interface IBiometricsFace extends @1.0::IBiometricsFace {
-    /**
-     * Enrolls a user's face for a remote client, for example Android Auto.
-     *
-     * The HAL implementation is responsible for creating a secure communication
-     * channel and receiving the enrollment images from a mobile device with
-     * face authentication hardware.
-     *
-     * Note that the Hardware Authentication Token must be valid for the
-     * duration of enrollment and thus should be explicitly invalidated by a
-     * call to revokeChallenge() when enrollment is complete, to reduce the
-     * window of opportunity to re-use the challenge and HAT. For example,
-     * Settings calls generateChallenge() once to allow the user to enroll one
-     * or more faces or toggle secure settings without having to re-enter the
-     * PIN/pattern/password. Once the user completes the operation, Settings
-     * invokes revokeChallenge() to close the transaction. If the HAT is expired,
-     * the implementation must invoke onError with UNABLE_TO_PROCESS.
-     *
-     * Requirements for using this API:
-     * - Mobile devices MUST NOT delegate enrollment to another device by calling
-     * this API. This feature is intended only to allow enrollment on devices
-     * where it is impossible to enroll locally on the device.
-     * - The path MUST be protected by a secret key with rollback protection.
-     * - Synchronizing between devices MUST be accomplished by having both
-     * devices agree on a secret PIN entered by the user (similar to BT
-     * pairing procedure) and use a salted version of that PIN plus other secret
-     * to encrypt traffic.
-     * - All communication to/from the remote device MUST be encrypted and signed
-     * to prevent image injection and other man-in-the-middle type attacks.
-     * - generateChallenge() and revokeChallenge() MUST be implemented on both
-     * remote and local host (e.g. hash the result of the remote host with a
-     * local secret before responding to the API call) and any transmission of
-     * the challenge between hosts MUST be signed to prevent man-in-the-middle
-     * attacks.
-     * - In the event of a lost connection, the result of the last
-     * generateChallenge() MUST be invalidated and the process started over.
-     * - Both the remote and local host MUST honor the timeout and invalidate the
-     * challenge.
-     *
-     * This method triggers the IBiometricsFaceClientCallback#onEnrollResult()
-     * method.
-     *
-     * @param hat A valid Hardware Authentication Token, generated as a result
-     *     of a generateChallenge() challenge being wrapped by the gatekeeper
-     *     after a successful strong authentication request.
-     * @param timeoutSec A timeout in seconds, after which this enroll
-     *     attempt is cancelled. Note that the framework can continue
-     *     enrollment by calling this again with a valid HAT. This timeout is
-     *     expected to be used to limit power usage if the device becomes idle
-     *     during enrollment. The implementation is expected to send
-     *     ERROR_TIMEOUT if this happens.
-     * @param disabledFeatures A list of features to be disabled during
-     *     enrollment. Note that all features are enabled by default.
-     * @return status The status of this method call.
-     */
-    enrollRemotely(vec<uint8_t> hat, uint32_t timeoutSec, vec<Feature> disabledFeatures)
-        generates (Status status);
-
-    /**
-     * Enrolls a user's face.
-     *
-     * Note that the Hardware Authentication Token must be valid for the
-     * duration of enrollment and thus should be explicitly invalidated by a
-     * call to revokeChallenge() when enrollment is complete, to reduce the
-     * window of opportunity to re-use the challenge and HAT. For example,
-     * Settings calls generateChallenge() once to allow the user to enroll one
-     * or more faces or toggle secure settings without having to re-enter the
-     * PIN/pattern/password. Once the user completes the operation, Settings
-     * invokes revokeChallenge() to close the transaction. If the HAT is expired,
-     * the implementation must invoke onError with UNABLE_TO_PROCESS.
-     *
-     * This method triggers the IBiometricsFaceClientCallback#onEnrollResult()
-     * method.
-     *
-     * @param hat A valid Hardware Authentication Token, generated as a result
-     *     of a generateChallenge() challenge being wrapped by the gatekeeper
-     *     after a successful strong authentication request.
-     * @param timeoutSec A timeout in seconds, after which this enroll
-     *     attempt is cancelled. Note that the framework can continue
-     *     enrollment by calling this again with a valid HAT. This timeout is
-     *     expected to be used to limit power usage if the device becomes idle
-     *     during enrollment. The implementation is expected to send
-     *     ERROR_TIMEOUT if this happens.
-     * @param disabledFeatures A list of features to be disabled during
-     *     enrollment. Note that all features are enabled by default.
-     * @param windowId optional ID of a camera preview window for a
-     *     single-camera device. Must be null if not used.
-     * @return status The status of this method call.
-     */
-    enroll_1_1(vec<uint8_t> hat, uint32_t timeoutSec, vec<Feature> disabledFeatures,
-        handle windowId) generates (Status status);
-};
diff --git a/biometrics/face/1.1/vts/functional/Android.bp b/biometrics/face/1.1/vts/functional/Android.bp
deleted file mode 100644
index aa0b1fa..0000000
--- a/biometrics/face/1.1/vts/functional/Android.bp
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 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.
- */
-
-cc_test {
-    name: "VtsHalBiometricsFaceV1_1TargetTest",
-    defaults: ["VtsHalTargetTestDefaults"],
-    srcs: ["VtsHalBiometricsFaceV1_1TargetTest.cpp"],
-    static_libs: [
-        "android.hardware.biometrics.face@1.0",
-        "android.hardware.biometrics.face@1.1",
-    ],
-    test_suites: [
-        "general-tests",
-        "vts",
-    ],
-}
diff --git a/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp
deleted file mode 100644
index 0077c8c..0000000
--- a/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright 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 "biometrics_face_hidl_hal_test"
-
-#include <android/hardware/biometrics/face/1.0/IBiometricsFaceClientCallback.h>
-#include <android/hardware/biometrics/face/1.1/IBiometricsFace.h>
-
-#include <VtsHalHidlTargetCallbackBase.h>
-#include <android-base/logging.h>
-#include <gtest/gtest.h>
-#include <hidl/GtestPrinter.h>
-#include <hidl/ServiceManagement.h>
-
-#include <chrono>
-#include <cstdint>
-#include <random>
-
-using android::sp;
-using android::hardware::hidl_handle;
-using android::hardware::hidl_vec;
-using android::hardware::Return;
-using android::hardware::Void;
-using android::hardware::biometrics::face::V1_0::FaceAcquiredInfo;
-using android::hardware::biometrics::face::V1_0::FaceError;
-using android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback;
-using android::hardware::biometrics::face::V1_0::OptionalUint64;
-using android::hardware::biometrics::face::V1_0::Status;
-using android::hardware::biometrics::face::V1_1::IBiometricsFace;
-
-namespace {
-
-// Arbitrary, nonexistent userId
-constexpr uint32_t kUserId = 9;
-constexpr uint32_t kTimeoutSec = 3;
-constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec);
-constexpr char kFacedataDir[] = "/data/vendor_de/0/facedata";
-constexpr char kCallbackNameOnError[] = "onError";
-
-// Callback arguments that need to be captured for the tests.
-struct FaceCallbackArgs {
-    // The error passed to the last onError() callback.
-    FaceError error;
-
-    // The userId passed to the last callback.
-    int32_t userId;
-};
-
-// Test callback class for the BiometricsFace HAL.
-// The HAL will call these callback methods to notify about completed operations
-// or encountered errors.
-class FaceCallback : public ::testing::VtsHalHidlTargetCallbackBase<FaceCallbackArgs>,
-                     public IBiometricsFaceClientCallback {
-  public:
-    Return<void> onEnrollResult(uint64_t, uint32_t, int32_t, uint32_t) override { return Void(); }
-
-    Return<void> onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec<uint8_t>&) override {
-        return Void();
-    }
-
-    Return<void> onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override {
-        return Void();
-    }
-
-    Return<void> onError(uint64_t, int32_t userId, FaceError error, int32_t) override {
-        FaceCallbackArgs args = {};
-        args.error = error;
-        args.userId = userId;
-        NotifyFromCallback(kCallbackNameOnError, args);
-        return Void();
-    }
-
-    Return<void> onRemoved(uint64_t, const hidl_vec<uint32_t>&, int32_t) override { return Void(); }
-
-    Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t) override {
-        return Void();
-    }
-
-    Return<void> onLockoutChanged(uint64_t) override { return Void(); }
-};
-
-// Test class for the BiometricsFace HAL.
-class FaceHidlTest : public ::testing::TestWithParam<std::string> {
-  public:
-    void SetUp() override {
-        mService = IBiometricsFace::getService(GetParam());
-        ASSERT_NE(mService, nullptr);
-        mCallback = new FaceCallback();
-        mCallback->SetWaitTimeoutDefault(kTimeout);
-        Return<void> ret1 = mService->setCallback(mCallback, [](const OptionalUint64& res) {
-            ASSERT_EQ(Status::OK, res.status);
-            // Makes sure the "deviceId" represented by "res.value" is not 0.
-            // 0 would mean the HIDL is not available.
-            ASSERT_NE(0UL, res.value);
-        });
-        ASSERT_TRUE(ret1.isOk());
-        Return<Status> ret2 = mService->setActiveUser(kUserId, kFacedataDir);
-        ASSERT_EQ(Status::OK, static_cast<Status>(ret2));
-    }
-
-    void TearDown() override {}
-
-    sp<IBiometricsFace> mService;
-    sp<FaceCallback> mCallback;
-};
-
-// enroll with an invalid (all zeroes) HAT should fail.
-TEST_P(FaceHidlTest, Enroll1_1ZeroHatTest) {
-    // Filling HAT with zeros
-    hidl_vec<uint8_t> token(69);
-    for (size_t i = 0; i < 69; i++) {
-        token[i] = 0;
-    }
-
-    hidl_handle windowId = nullptr;
-    Return<Status> ret = mService->enroll_1_1(token, kTimeoutSec, {}, windowId);
-    ASSERT_EQ(Status::OK, static_cast<Status>(ret));
-
-    // onError should be called with a meaningful (nonzero) error.
-    auto res = mCallback->WaitForCallback(kCallbackNameOnError);
-    EXPECT_TRUE(res.no_timeout);
-    EXPECT_EQ(kUserId, res.args->userId);
-    EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
-}
-
-// enroll with an invalid HAT should fail.
-TEST_P(FaceHidlTest, Enroll1_1GarbageHatTest) {
-    // Filling HAT with pseudorandom invalid data.
-    // Using default seed to make the test reproducible.
-    std::mt19937 gen(std::mt19937::default_seed);
-    std::uniform_int_distribution<uint8_t> dist;
-    hidl_vec<uint8_t> token(69);
-    for (size_t i = 0; i < 69; ++i) {
-        token[i] = dist(gen);
-    }
-
-    hidl_handle windowId = nullptr;
-    Return<Status> ret = mService->enroll_1_1(token, kTimeoutSec, {}, windowId);
-    ASSERT_EQ(Status::OK, static_cast<Status>(ret));
-
-    // onError should be called with a meaningful (nonzero) error.
-    auto res = mCallback->WaitForCallback(kCallbackNameOnError);
-    EXPECT_TRUE(res.no_timeout);
-    EXPECT_EQ(kUserId, res.args->userId);
-    EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
-}
-
-// enroll with an invalid (all zeroes) HAT should fail.
-TEST_P(FaceHidlTest, EnrollRemotelyZeroHatTest) {
-    // Filling HAT with zeros
-    hidl_vec<uint8_t> token(69);
-    for (size_t i = 0; i < 69; i++) {
-        token[i] = 0;
-    }
-
-    Return<Status> ret = mService->enrollRemotely(token, kTimeoutSec, {});
-    ASSERT_EQ(Status::OK, static_cast<Status>(ret));
-
-    // onError should be called with a meaningful (nonzero) error.
-    auto res = mCallback->WaitForCallback(kCallbackNameOnError);
-    EXPECT_TRUE(res.no_timeout);
-    EXPECT_EQ(kUserId, res.args->userId);
-    EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
-}
-
-// enroll with an invalid HAT should fail.
-TEST_P(FaceHidlTest, EnrollRemotelyGarbageHatTest) {
-    // Filling HAT with pseudorandom invalid data.
-    // Using default seed to make the test reproducible.
-    std::mt19937 gen(std::mt19937::default_seed);
-    std::uniform_int_distribution<uint8_t> dist;
-    hidl_vec<uint8_t> token(69);
-    for (size_t i = 0; i < 69; ++i) {
-        token[i] = dist(gen);
-    }
-
-    Return<Status> ret = mService->enrollRemotely(token, kTimeoutSec, {});
-    ASSERT_EQ(Status::OK, static_cast<Status>(ret));
-
-    // onError should be called with a meaningful (nonzero) error.
-    auto res = mCallback->WaitForCallback(kCallbackNameOnError);
-    EXPECT_TRUE(res.no_timeout);
-    EXPECT_EQ(kUserId, res.args->userId);
-    EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
-}
-
-}  // anonymous namespace
-
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FaceHidlTest);
-INSTANTIATE_TEST_SUITE_P(
-        PerInstance, FaceHidlTest,
-        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBiometricsFace::descriptor)),
-        android::hardware::PrintInstanceNameToString);
diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp
index c8cb663..24087cf 100644
--- a/biometrics/fingerprint/aidl/default/Android.bp
+++ b/biometrics/fingerprint/aidl/default/Android.bp
@@ -1,18 +1,32 @@
 cc_binary {
     name: "android.hardware.biometrics.fingerprint-service.example",
+    vendor: true,
     relative_install_path: "hw",
     init_rc: ["fingerprint-default.rc"],
     vintf_fragments: ["fingerprint-default.xml"],
-    vendor: true,
+    local_include_dirs: ["include"],
+    srcs: [
+        "main.cpp",
+        "Fingerprint.cpp",
+        "Session.cpp",
+    ],
     shared_libs: [
         "libbase",
         "libbinder_ndk",
         "android.hardware.biometrics.fingerprint-V1-ndk_platform",
         "android.hardware.biometrics.common-V1-ndk_platform",
     ],
+}
+
+cc_test_host {
+    name: "android.hardware.biometrics.fingerprint.WorkerThreadTest",
+    local_include_dirs: ["include"],
     srcs: [
-        "main.cpp",
-        "Fingerprint.cpp",
-        "Session.cpp",
+        "tests/WorkerThreadTest.cpp",
+        "WorkerThread.cpp",
     ],
+    shared_libs: [
+        "libcutils",
+    ],
+    test_suites: ["general-tests"],
 }
diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.cpp b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
index f27e278..fa3171f 100644
--- a/biometrics/fingerprint/aidl/default/Fingerprint.cpp
+++ b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
@@ -18,50 +18,44 @@
 #include "Session.h"
 
 namespace aidl::android::hardware::biometrics::fingerprint {
+namespace {
 
-const int kSensorId = 1;
-const common::SensorStrength kSensorStrength = common::SensorStrength::STRONG;
-const int kMaxEnrollmentsPerUser = 5;
-const FingerprintSensorType kSensorType = FingerprintSensorType::REAR;
-const bool kSupportsNavigationGestures = true;
-const std::string kHwDeviceName = "fingerprintSensor";
-const std::string kHardwareVersion = "vendor/model/revision";
-const std::string kFirmwareVersion = "1.01";
-const std::string kSerialNumber = "00000001";
+constexpr int SENSOR_ID = 1;
+constexpr common::SensorStrength SENSOR_STRENGTH = common::SensorStrength::STRONG;
+constexpr int MAX_ENROLLMENTS_PER_USER = 5;
+constexpr FingerprintSensorType SENSOR_TYPE = FingerprintSensorType::REAR;
+constexpr bool SUPPORTS_NAVIGATION_GESTURES = true;
+constexpr char HW_DEVICE_NAME[] = "fingerprintSensor";
+constexpr char HW_VERSION[] = "vendor/model/revision";
+constexpr char FW_VERSION[] = "1.01";
+constexpr char SERIAL_NUMBER[] = "00000001";
 
-ndk::ScopedAStatus Fingerprint::getSensorProps(std::vector<SensorProps>* return_val) {
-    *return_val = std::vector<SensorProps>();
+}  // namespace
 
-    std::vector<common::HardwareInfo> hardwareInfos = std::vector<common::HardwareInfo>();
-    common::HardwareInfo sensorInfo = {kHwDeviceName,
-            kHardwareVersion,
-            kFirmwareVersion,
-            kSerialNumber
-    };
-    hardwareInfos.push_back(sensorInfo);
-    common::CommonProps commonProps = {kSensorId,
-            kSensorStrength,
-            kMaxEnrollmentsPerUser,
-            hardwareInfos};
-    SensorLocation sensorLocation = {
-            0 /* displayId */,
-            0 /* sensorLocationX */,
-            0 /* sensorLocationY */,
-            0 /* sensorRadius */
-    };
-    SensorProps props = {commonProps,
-            kSensorType,
-            {sensorLocation},
-            kSupportsNavigationGestures,
-            false /* supportsDetectInteraction */};
-    return_val->push_back(props);
+Fingerprint::Fingerprint() {}
+
+ndk::ScopedAStatus Fingerprint::getSensorProps(std::vector<SensorProps>* out) {
+    std::vector<common::HardwareInfo> hardwareInfos = {
+            {HW_DEVICE_NAME, HW_VERSION, FW_VERSION, SERIAL_NUMBER}};
+
+    common::CommonProps commonProps = {SENSOR_ID, SENSOR_STRENGTH, MAX_ENROLLMENTS_PER_USER,
+                                       hardwareInfos};
+
+    SensorLocation sensorLocation = {0 /* displayId */, 0 /* sensorLocationX */,
+                                     0 /* sensorLocationY */, 0 /* sensorRadius */};
+
+    *out = {{commonProps,
+             SENSOR_TYPE,
+             {sensorLocation},
+             SUPPORTS_NAVIGATION_GESTURES,
+             false /* supportsDetectInteraction */}};
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Fingerprint::createSession(int32_t /*sensorId*/, int32_t /*userId*/,
                                               const std::shared_ptr<ISessionCallback>& cb,
-                                              std::shared_ptr<ISession>* return_val) {
-    *return_val = SharedRefBase::make<Session>(cb);
+                                              std::shared_ptr<ISession>* out) {
+    *out = SharedRefBase::make<Session>(cb);
     return ndk::ScopedAStatus::ok();
 }
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/Session.cpp b/biometrics/fingerprint/aidl/default/Session.cpp
index 8446221..52dddb6 100644
--- a/biometrics/fingerprint/aidl/default/Session.cpp
+++ b/biometrics/fingerprint/aidl/default/Session.cpp
@@ -26,7 +26,7 @@
     ndk::ScopedAStatus cancel() override { return ndk::ScopedAStatus::ok(); }
 };
 
-Session::Session(std::shared_ptr<ISessionCallback> cb) : cb_(std::move(cb)) {}
+Session::Session(std::shared_ptr<ISessionCallback> cb) : mCb(std::move(cb)) {}
 
 ndk::ScopedAStatus Session::generateChallenge(int32_t /*cookie*/, int32_t /*timeoutSec*/) {
     LOG(INFO) << "generateChallenge";
@@ -39,32 +39,32 @@
 }
 
 ndk::ScopedAStatus Session::enroll(int32_t /*cookie*/, const keymaster::HardwareAuthToken& /*hat*/,
-                                   std::shared_ptr<common::ICancellationSignal>* /*return_val*/) {
+                                   std::shared_ptr<common::ICancellationSignal>* /*out*/) {
     LOG(INFO) << "enroll";
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::authenticate(int32_t /*cookie*/, int64_t /*keystoreOperationId*/,
-                                         std::shared_ptr<common::ICancellationSignal>* return_val) {
+                                         std::shared_ptr<common::ICancellationSignal>* out) {
     LOG(INFO) << "authenticate";
-    if (cb_) {
-        cb_->onStateChanged(0, SessionState::AUTHENTICATING);
+    if (mCb) {
+        mCb->onStateChanged(0, SessionState::AUTHENTICATING);
     }
-    *return_val = SharedRefBase::make<CancellationSignal>();
+    *out = SharedRefBase::make<CancellationSignal>();
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::detectInteraction(
-        int32_t /*cookie*/, std::shared_ptr<common::ICancellationSignal>* /*return_val*/) {
+        int32_t /*cookie*/, std::shared_ptr<common::ICancellationSignal>* /*out*/) {
     LOG(INFO) << "detectInteraction";
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::enumerateEnrollments(int32_t /*cookie*/) {
     LOG(INFO) << "enumerateEnrollments";
-    if (cb_) {
-        cb_->onStateChanged(0, SessionState::ENUMERATING_ENROLLMENTS);
-        cb_->onEnrollmentsEnumerated(std::vector<int32_t>());
+    if (mCb) {
+        mCb->onStateChanged(0, SessionState::ENUMERATING_ENROLLMENTS);
+        mCb->onEnrollmentsEnumerated(std::vector<int32_t>());
     }
     return ndk::ScopedAStatus::ok();
 }
@@ -72,18 +72,18 @@
 ndk::ScopedAStatus Session::removeEnrollments(int32_t /*cookie*/,
                                               const std::vector<int32_t>& /*enrollmentIds*/) {
     LOG(INFO) << "removeEnrollments";
-    if (cb_) {
-        cb_->onStateChanged(0, SessionState::REMOVING_ENROLLMENTS);
-        cb_->onEnrollmentsRemoved(std::vector<int32_t>());
+    if (mCb) {
+        mCb->onStateChanged(0, SessionState::REMOVING_ENROLLMENTS);
+        mCb->onEnrollmentsRemoved(std::vector<int32_t>());
     }
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::getAuthenticatorId(int32_t /*cookie*/) {
     LOG(INFO) << "getAuthenticatorId";
-    if (cb_) {
-        cb_->onStateChanged(0, SessionState::GETTING_AUTHENTICATOR_ID);
-        cb_->onAuthenticatorIdRetrieved(0 /* authenticatorId */);
+    if (mCb) {
+        mCb->onStateChanged(0, SessionState::GETTING_AUTHENTICATOR_ID);
+        mCb->onAuthenticatorIdRetrieved(0 /* authenticatorId */);
     }
     return ndk::ScopedAStatus::ok();
 }
diff --git a/biometrics/fingerprint/aidl/default/WorkerThread.cpp b/biometrics/fingerprint/aidl/default/WorkerThread.cpp
new file mode 100644
index 0000000..512efb8
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/WorkerThread.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "WorkerThread.h"
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+// It's important that mThread is initialized after everything else because it runs a member
+// function that may use any member of this class.
+WorkerThread::WorkerThread(size_t maxQueueSize)
+    : mMaxSize(maxQueueSize),
+      mIsDestructing(false),
+      mQueue(),
+      mQueueMutex(),
+      mQueueCond(),
+      mThread(&WorkerThread::threadFunc, this) {}
+
+WorkerThread::~WorkerThread() {
+    // This is a signal for threadFunc to terminate as soon as possible, and a hint for schedule
+    // that it doesn't need to do any work.
+    mIsDestructing = true;
+    mQueueCond.notify_all();
+    mThread.join();
+}
+
+bool WorkerThread::schedule(Task&& task) {
+    if (mIsDestructing) {
+        return false;
+    }
+
+    std::unique_lock<std::mutex> lock(mQueueMutex);
+    if (mQueue.size() >= mMaxSize) {
+        return false;
+    }
+    mQueue.push_back(std::move(task));
+    lock.unlock();
+    mQueueCond.notify_one();
+    return true;
+}
+
+void WorkerThread::threadFunc() {
+    while (!mIsDestructing) {
+        std::unique_lock<std::mutex> lock(mQueueMutex);
+        mQueueCond.wait(lock, [this] { return !mQueue.empty() || mIsDestructing; });
+        if (mIsDestructing) {
+            return;
+        }
+        Task task = std::move(mQueue.front());
+        mQueue.pop_front();
+        lock.unlock();
+        task();
+    }
+}
+
+}  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.h b/biometrics/fingerprint/aidl/default/include/Fingerprint.h
similarity index 91%
rename from biometrics/fingerprint/aidl/default/Fingerprint.h
rename to biometrics/fingerprint/aidl/default/include/Fingerprint.h
index 4e952ba..867e5fa 100644
--- a/biometrics/fingerprint/aidl/default/Fingerprint.h
+++ b/biometrics/fingerprint/aidl/default/include/Fingerprint.h
@@ -20,13 +20,15 @@
 
 namespace aidl::android::hardware::biometrics::fingerprint {
 
-class Fingerprint : public BnFingerprint {
+class Fingerprint final : public BnFingerprint {
   public:
-    ndk::ScopedAStatus getSensorProps(std::vector<SensorProps>* _aidl_return) override;
+    Fingerprint();
+
+    ndk::ScopedAStatus getSensorProps(std::vector<SensorProps>* out) override;
 
     ndk::ScopedAStatus createSession(int32_t sensorId, int32_t userId,
                                      const std::shared_ptr<ISessionCallback>& cb,
-                                     std::shared_ptr<ISession>* _aidl_return) override;
+                                     std::shared_ptr<ISession>* out) override;
 };
 
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/Session.h b/biometrics/fingerprint/aidl/default/include/Session.h
similarity index 89%
rename from biometrics/fingerprint/aidl/default/Session.h
rename to biometrics/fingerprint/aidl/default/include/Session.h
index ed3ae3f..b9befef 100644
--- a/biometrics/fingerprint/aidl/default/Session.h
+++ b/biometrics/fingerprint/aidl/default/include/Session.h
@@ -33,14 +33,13 @@
     ndk::ScopedAStatus revokeChallenge(int32_t cookie, int64_t challenge) override;
 
     ndk::ScopedAStatus enroll(int32_t cookie, const keymaster::HardwareAuthToken& hat,
-                              std::shared_ptr<common::ICancellationSignal>* return_val) override;
+                              std::shared_ptr<common::ICancellationSignal>* out) override;
 
-    ndk::ScopedAStatus authenticate(
-            int32_t cookie, int64_t keystoreOperationId,
-            std::shared_ptr<common::ICancellationSignal>* return_val) override;
+    ndk::ScopedAStatus authenticate(int32_t cookie, int64_t keystoreOperationId,
+                                    std::shared_ptr<common::ICancellationSignal>* out) override;
 
     ndk::ScopedAStatus detectInteraction(
-            int32_t cookie, std::shared_ptr<common::ICancellationSignal>* return_val) override;
+            int32_t cookie, std::shared_ptr<common::ICancellationSignal>* out) override;
 
     ndk::ScopedAStatus enumerateEnrollments(int32_t cookie) override;
 
@@ -62,7 +61,7 @@
     ndk::ScopedAStatus onUiReady() override;
 
   private:
-    std::shared_ptr<ISessionCallback> cb_;
+    std::shared_ptr<ISessionCallback> mCb;
 };
 
 }  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/include/WorkerThread.h b/biometrics/fingerprint/aidl/default/include/WorkerThread.h
new file mode 100644
index 0000000..49104c8
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/include/WorkerThread.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <mutex>
+#include <optional>
+#include <queue>
+#include <thread>
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+using Task = std::function<void()>;
+
+// A class that encapsulates a worker thread and a task queue, and provides a convenient interface
+// for a Session to schedule its tasks for asynchronous execution.
+class WorkerThread final {
+  public:
+    // Internally creates a queue that cannot exceed maxQueueSize elements and a new thread that
+    // polls the queue for tasks until this instance is destructed.
+    explicit WorkerThread(size_t maxQueueSize);
+
+    // Unblocks the internal queue and calls join on the internal thread allowing it to gracefully
+    // exit.
+    ~WorkerThread();
+
+    // Disallow copying this class.
+    WorkerThread(const WorkerThread&) = delete;
+    WorkerThread& operator=(const WorkerThread&) = delete;
+
+    // Also disable moving this class to simplify implementation.
+    WorkerThread(WorkerThread&&) = delete;
+    WorkerThread& operator=(WorkerThread&&) = delete;
+
+    // If the internal queue is not full, pushes a task at the end of the queue and returns true.
+    // Otherwise, returns false. If the queue is busy, blocks until it becomes available.
+    bool schedule(Task&& task);
+
+  private:
+    // The function that runs on the internal thread. Sequentially runs the available tasks from
+    // the queue. If the queue is empty, waits until a new task is added. If the worker is being
+    // destructed, finishes its current task and gracefully exits.
+    void threadFunc();
+
+    // The maximum size that the queue is allowed to expand to.
+    size_t mMaxSize;
+
+    // Whether the destructor was called. If true, tells threadFunc to exit as soon as possible, and
+    // tells schedule to avoid doing any work.
+    std::atomic<bool> mIsDestructing;
+
+    // Queue that's guarded by mQueueMutex and mQueueCond.
+    std::deque<Task> mQueue;
+    std::mutex mQueueMutex;
+    std::condition_variable mQueueCond;
+
+    // The internal thread that works on the tasks from the queue.
+    std::thread mThread;
+};
+
+}  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp b/biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp
new file mode 100644
index 0000000..ba901ad
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <chrono>
+#include <future>
+#include <thread>
+
+#include <gtest/gtest.h>
+
+#include "WorkerThread.h"
+
+namespace {
+
+using aidl::android::hardware::biometrics::fingerprint::WorkerThread;
+using namespace std::chrono_literals;
+
+TEST(WorkerThreadTest, ScheduleReturnsTrueWhenQueueHasSpace) {
+    WorkerThread worker(1 /*maxQueueSize*/);
+    for (int i = 0; i < 100; ++i) {
+        EXPECT_TRUE(worker.schedule([] {}));
+        // Allow enough time for the previous task to be processed.
+        std::this_thread::sleep_for(2ms);
+    }
+}
+
+TEST(WorkerThreadTest, ScheduleReturnsFalseWhenQueueIsFull) {
+    WorkerThread worker(2 /*maxQueueSize*/);
+    // Add a long-running task.
+    worker.schedule([] { std::this_thread::sleep_for(1s); });
+
+    // Allow enough time for the worker to start working on the previous task.
+    std::this_thread::sleep_for(2ms);
+
+    // Fill the worker's queue to the maximum.
+    worker.schedule([] {});
+    worker.schedule([] {});
+
+    EXPECT_FALSE(worker.schedule([] {}));
+}
+
+TEST(WorkerThreadTest, TasksExecuteInOrder) {
+    constexpr int NUM_TASKS = 10000;
+    WorkerThread worker(NUM_TASKS);
+
+    std::vector<int> results;
+    for (int i = 0; i < NUM_TASKS; ++i) {
+        worker.schedule([&results, i] {
+            // Delay tasks differently to provoke races.
+            std::this_thread::sleep_for(std::chrono::nanoseconds(100 - i % 100));
+            // Unguarded write to results to provoke races.
+            results.push_back(i);
+        });
+    }
+
+    std::promise<void> promise;
+    auto future = promise.get_future();
+
+    // Schedule a special task to signal when all of the tasks are finished.
+    worker.schedule([&promise] { promise.set_value(); });
+    auto status = future.wait_for(1s);
+    ASSERT_EQ(status, std::future_status::ready);
+
+    ASSERT_EQ(results.size(), NUM_TASKS);
+    EXPECT_TRUE(std::is_sorted(results.begin(), results.end()));
+}
+
+TEST(WorkerThreadTest, ExecutionStopsAfterWorkerIsDestroyed) {
+    std::promise<void> promise1;
+    std::promise<void> promise2;
+    auto future1 = promise1.get_future();
+    auto future2 = promise2.get_future();
+
+    {
+        WorkerThread worker(2 /*maxQueueSize*/);
+        worker.schedule([&promise1] {
+            promise1.set_value();
+            std::this_thread::sleep_for(200ms);
+        });
+        worker.schedule([&promise2] { promise2.set_value(); });
+
+        // Make sure the first task is executing.
+        auto status1 = future1.wait_for(1s);
+        ASSERT_EQ(status1, std::future_status::ready);
+    }
+
+    // The second task should never execute.
+    auto status2 = future2.wait_for(1s);
+    EXPECT_EQ(status2, std::future_status::timeout);
+}
+
+}  // namespace
diff --git a/camera/metadata/3.6/Android.bp b/camera/metadata/3.6/Android.bp
new file mode 100644
index 0000000..d9f3fb8
--- /dev/null
+++ b/camera/metadata/3.6/Android.bp
@@ -0,0 +1,16 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.camera.metadata@3.6",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+    ],
+    interfaces: [
+        "android.hardware.camera.metadata@3.2",
+        "android.hardware.camera.metadata@3.3",
+        "android.hardware.camera.metadata@3.4",
+        "android.hardware.camera.metadata@3.5",
+    ],
+    gen_java: true,
+}
diff --git a/camera/metadata/3.6/types.hal b/camera/metadata/3.6/types.hal
new file mode 100644
index 0000000..fb95736
--- /dev/null
+++ b/camera/metadata/3.6/types.hal
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata@3.6;
+
+import android.hardware.camera.metadata@3.2;
+import android.hardware.camera.metadata@3.3;
+import android.hardware.camera.metadata@3.4;
+import android.hardware.camera.metadata@3.5;
+
+// No new metadata sections added in this revision
+
+/**
+ * Main enumeration for defining camera metadata tags added in this revision
+ *
+ * <p>Partial documentation is included for each tag; for complete documentation, reference
+ * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
+ */
+enum CameraMetadataTag : @3.5::CameraMetadataTag {
+    /** android.scaler.defaultSecureImageSize [static, int32[], public]
+     *
+     * <p>Default YUV/PRIVATE size to use for requesting secure image buffers.</p>
+     */
+    ANDROID_SCALER_DEFAULT_SECURE_IMAGE_SIZE = android.hardware.camera.metadata@3.5::CameraMetadataTag:ANDROID_SCALER_END_3_5,
+
+    ANDROID_SCALER_END_3_6,
+
+};
+
+/*
+ * Enumeration definitions for the various entries that need them
+ */
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 48f0b60..6562f22 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -95,7 +95,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.biometrics.face</name>
-        <version>1.0-1</version>
+        <version>1.0</version>
         <interface>
             <name>IBiometricsFace</name>
             <instance>default</instance>
@@ -343,6 +343,13 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.security.keymint</name>
+        <interface>
+            <name>IRemotelyProvisionedComponent</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.light</name>
         <version>1</version>
         <interface>
@@ -554,7 +561,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.tv.cec</name>
-        <version>1.0</version>
+        <version>1.0-1</version>
         <interface>
             <name>IHdmiCec</name>
             <instance>default</instance>
diff --git a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
index 8a90173..356ad97 100644
--- a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
+++ b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
@@ -52,40 +52,17 @@
 using ::android::hardware::contexthub::vts_utils::ContexthubHidlTestBase;
 using ::android::hardware::contexthub::vts_utils::getHalAndHubIdList;
 using ::android::hardware::contexthub::vts_utils::getHubsSync;
+using ::android::hardware::contexthub::vts_utils::kNonExistentAppId;
+using ::android::hardware::contexthub::vts_utils::waitForCallback;
 
 namespace {
 
-// App ID with vendor "GoogT" (Google Testing), app identifier 0x555555. This
-// app ID is reserved and must never appear in the list of loaded apps.
-constexpr uint64_t kNonExistentAppId = 0x476f6f6754555555;
-
 const std::vector<std::tuple<std::string, std::string>> kTestParameters =
         getHalAndHubIdList<IContexthub>();
 
 class ContexthubHidlTest : public ContexthubHidlTestBase<IContexthub> {};
 
-// Wait for a callback to occur (signaled by the given future) up to the
-// provided timeout. If the future is invalid or the callback does not come
-// within the given time, returns false.
-template <class ReturnType>
-bool waitForCallback(std::future<ReturnType> future, ReturnType* result,
-                     std::chrono::milliseconds timeout = std::chrono::seconds(5)) {
-    auto expiration = std::chrono::system_clock::now() + timeout;
-
-    EXPECT_NE(result, nullptr);
-    EXPECT_TRUE(future.valid());
-    if (result != nullptr && future.valid()) {
-        std::future_status status = future.wait_until(expiration);
-        EXPECT_NE(status, std::future_status::timeout) << "Timed out waiting for callback";
-
-        if (status == std::future_status::ready) {
-            *result = future.get();
-            return true;
-        }
-    }
-
-    return false;
-}
+class ContexthubCallbackV1_0 : public ContexthubCallbackBase<IContexthubCallback> {};
 
 // Ensures that the metadata reported in getHubs() is sane
 TEST_P(ContexthubHidlTest, TestGetHubs) {
@@ -110,7 +87,7 @@
 
 TEST_P(ContexthubHidlTest, TestRegisterCallback) {
     ALOGD("TestRegisterCallback called, hubId %" PRIu32, getHubId());
-    ASSERT_OK(registerCallback(new ContexthubCallbackBase()));
+    ASSERT_OK(registerCallback(new ContexthubCallbackV1_0()));
 }
 
 TEST_P(ContexthubHidlTest, TestRegisterNullCallback) {
@@ -119,7 +96,7 @@
 }
 
 // Helper callback that puts the async appInfo callback data into a promise
-class QueryAppsCallback : public ContexthubCallbackBase {
+class QueryAppsCallback : public ContexthubCallbackV1_0 {
   public:
     virtual Return<void> handleAppsInfo(const hidl_vec<HubAppInfo>& appInfo) override {
         ALOGD("Got app info callback with %zu apps", appInfo.size());
@@ -150,7 +127,7 @@
 
 // Helper callback that puts the TransactionResult for the expectedTxnId into a
 // promise
-class TxnResultCallback : public ContexthubCallbackBase {
+class TxnResultCallback : public ContexthubCallbackV1_0 {
   public:
     virtual Return<void> handleTxnResult(uint32_t txnId, TransactionResult result) override {
         ALOGD("Got transaction result callback for txnId %" PRIu32 " (expecting %" PRIu32
diff --git a/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp b/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp
index 5f1dad9..acf4be0 100644
--- a/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp
+++ b/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp
@@ -31,6 +31,7 @@
 
 #include <cinttypes>
 
+using ::android::hardware::contexthub::V1_0::IContexthubCallback;
 using ::android::hardware::contexthub::V1_1::IContexthub;
 using ::android::hardware::contexthub::V1_1::Setting;
 using ::android::hardware::contexthub::V1_1::SettingValue;
@@ -45,10 +46,12 @@
 
 class ContexthubHidlTest : public ContexthubHidlTestBase<IContexthub> {};
 
+class ContexthubCallbackV1_0 : public ContexthubCallbackBase<IContexthubCallback> {};
+
 TEST_P(ContexthubHidlTest, TestOnSettingChanged) {
     // In VTS, we only test that sending the values doesn't cause things to blow up - other test
     // suites verify the expected E2E behavior in CHRE
-    ASSERT_OK(registerCallback(new ContexthubCallbackBase()));
+    ASSERT_OK(registerCallback(new ContexthubCallbackV1_0()));
     hubApi->onSettingChanged(Setting::LOCATION, SettingValue::DISABLED);
     hubApi->onSettingChanged(Setting::LOCATION, SettingValue::ENABLED);
     ASSERT_OK(registerCallback(nullptr));
diff --git a/contexthub/1.2/vts/functional/VtsHalContexthubV1_2TargetTest.cpp b/contexthub/1.2/vts/functional/VtsHalContexthubV1_2TargetTest.cpp
index 782edae..c50d43c 100644
--- a/contexthub/1.2/vts/functional/VtsHalContexthubV1_2TargetTest.cpp
+++ b/contexthub/1.2/vts/functional/VtsHalContexthubV1_2TargetTest.cpp
@@ -32,45 +32,202 @@
 
 #include <cinttypes>
 
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::contexthub::V1_0::ContextHub;
+using ::android::hardware::contexthub::V1_0::Result;
+using ::android::hardware::contexthub::V1_0::TransactionResult;
 using ::android::hardware::contexthub::V1_1::SettingValue;
+using ::android::hardware::contexthub::V1_2::ContextHubMsg;
+using ::android::hardware::contexthub::V1_2::HubAppInfo;
 using ::android::hardware::contexthub::V1_2::IContexthub;
+using ::android::hardware::contexthub::V1_2::IContexthubCallback;
 using ::android::hardware::contexthub::V1_2::Setting;
+using ::android::hardware::contexthub::vts_utils::asBaseType;
 using ::android::hardware::contexthub::vts_utils::ContexthubCallbackBase;
 using ::android::hardware::contexthub::vts_utils::ContexthubHidlTestBase;
 using ::android::hardware::contexthub::vts_utils::getHalAndHubIdList;
+using ::android::hardware::contexthub::vts_utils::kNonExistentAppId;
+using ::android::hardware::contexthub::vts_utils::waitForCallback;
 
 namespace {
 
 const std::vector<std::tuple<std::string, std::string>> kTestParameters =
         getHalAndHubIdList<IContexthub>();
 
-class ContexthubHidlTest : public ContexthubHidlTestBase<IContexthub> {};
+class ContexthubCallbackV1_2 : public ContexthubCallbackBase<IContexthubCallback> {
+  public:
+    virtual Return<void> handleClientMsg_1_2(
+            const ContextHubMsg& /*msg*/,
+            const hidl_vec<hidl_string>& /*msgContentPerms*/) override {
+        ALOGD("Got client message callback");
+        return Void();
+    }
+
+    virtual Return<void> handleAppsInfo_1_2(const hidl_vec<HubAppInfo>& /*appInfo*/) override {
+        ALOGD("Got app info callback");
+        return Void();
+    }
+};
+
+class ContexthubHidlTest : public ContexthubHidlTestBase<IContexthub> {
+  public:
+    Result registerCallback_1_2(sp<IContexthubCallback> cb) {
+        return hubApi->registerCallback_1_2(getHubId(), cb);
+    }
+};
+
+// Ensures that the metadata reported in getHubs_1_2() is valid
+TEST_P(ContexthubHidlTest, TestGetHubs_1_2) {
+    hidl_vec<ContextHub> hubList;
+    hubApi->getHubs_1_2(
+            [&hubList](const hidl_vec<ContextHub>& hubs,
+                       const hidl_vec<hidl_string>& /*hubPermissions*/) { hubList = hubs; });
+
+    ALOGD("System reports %zu hubs", hubList.size());
+
+    for (const ContextHub& hub : hubList) {
+        ALOGD("Checking hub ID %" PRIu32, hub.hubId);
+
+        EXPECT_FALSE(hub.name.empty());
+        EXPECT_FALSE(hub.vendor.empty());
+        EXPECT_FALSE(hub.toolchain.empty());
+        EXPECT_GT(hub.peakMips, 0);
+        EXPECT_GE(hub.stoppedPowerDrawMw, 0);
+        EXPECT_GE(hub.sleepPowerDrawMw, 0);
+        EXPECT_GT(hub.peakPowerDrawMw, 0);
+
+        // Minimum 128 byte MTU as required by CHRE API v1.0
+        EXPECT_GE(hub.maxSupportedMsgLen, UINT32_C(128));
+    }
+}
+
+TEST_P(ContexthubHidlTest, TestRegisterCallback) {
+    ALOGD("TestRegisterCallback called, hubId %" PRIu32, getHubId());
+    ASSERT_OK(registerCallback_1_2(new ContexthubCallbackV1_2()));
+}
+
+TEST_P(ContexthubHidlTest, TestRegisterNullCallback) {
+    ALOGD("TestRegisterNullCallback called, hubId %" PRIu32, getHubId());
+    ASSERT_OK(registerCallback_1_2(nullptr));
+}
 
 // In VTS, we only test that sending the values doesn't cause things to blow up - other test
 // suites verify the expected E2E behavior in CHRE
 TEST_P(ContexthubHidlTest, TestOnWifiSettingChanged) {
-    ASSERT_OK(registerCallback(new ContexthubCallbackBase()));
+    ASSERT_OK(registerCallback_1_2(new ContexthubCallbackV1_2()));
     hubApi->onSettingChanged_1_2(Setting::WIFI_AVAILABLE, SettingValue::DISABLED);
     hubApi->onSettingChanged_1_2(Setting::WIFI_AVAILABLE, SettingValue::ENABLED);
-    ASSERT_OK(registerCallback(nullptr));
+    ASSERT_OK(registerCallback_1_2(nullptr));
 }
 
 TEST_P(ContexthubHidlTest, TestOnAirplaneModeSettingChanged) {
-    ASSERT_OK(registerCallback(new ContexthubCallbackBase()));
+    ASSERT_OK(registerCallback_1_2(new ContexthubCallbackV1_2()));
     hubApi->onSettingChanged_1_2(Setting::AIRPLANE_MODE, SettingValue::DISABLED);
     hubApi->onSettingChanged_1_2(Setting::AIRPLANE_MODE, SettingValue::ENABLED);
-    ASSERT_OK(registerCallback(nullptr));
+    ASSERT_OK(registerCallback_1_2(nullptr));
 }
 
 TEST_P(ContexthubHidlTest, TestOnGlobalMicDisableSettingChanged) {
-    ASSERT_OK(registerCallback(new ContexthubCallbackBase()));
+    ASSERT_OK(registerCallback_1_2(new ContexthubCallbackV1_2()));
     hubApi->onSettingChanged_1_2(Setting::GLOBAL_MIC_DISABLE, SettingValue::DISABLED);
     hubApi->onSettingChanged_1_2(Setting::GLOBAL_MIC_DISABLE, SettingValue::ENABLED);
-    ASSERT_OK(registerCallback(nullptr));
+    ASSERT_OK(registerCallback_1_2(nullptr));
+}
+
+// Helper callback that puts the async appInfo callback data into a promise
+class QueryAppsCallback : public ContexthubCallbackV1_2 {
+  public:
+    virtual Return<void> handleAppsInfo_1_2(const hidl_vec<HubAppInfo>& appInfo) override {
+        ALOGD("Got app info callback with %zu apps", appInfo.size());
+        promise.set_value(appInfo);
+        return Void();
+    }
+
+    std::promise<hidl_vec<HubAppInfo>> promise;
+};
+
+// Calls queryApps() and checks the returned metadata
+TEST_P(ContexthubHidlTest, TestQueryApps) {
+    hidl_vec<hidl_string> hubPerms;
+    hubApi->getHubs_1_2([&hubPerms](const hidl_vec<ContextHub>& /*hubs*/,
+                                    const hidl_vec<hidl_string>& hubPermissions) {
+        hubPerms = hubPermissions;
+    });
+
+    ALOGD("TestQueryApps called, hubId %u", getHubId());
+    sp<QueryAppsCallback> cb = new QueryAppsCallback();
+    ASSERT_OK(registerCallback_1_2(cb));
+
+    Result result = hubApi->queryApps(getHubId());
+    ASSERT_OK(result);
+
+    ALOGD("Waiting for app info callback");
+    hidl_vec<HubAppInfo> appList;
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future(), &appList));
+    for (const HubAppInfo& appInfo : appList) {
+        EXPECT_NE(appInfo.info_1_0.appId, UINT64_C(0));
+        EXPECT_NE(appInfo.info_1_0.appId, kNonExistentAppId);
+        for (std::string permission : appInfo.permissions) {
+            ASSERT_TRUE(hubPerms.contains(permission));
+        }
+    }
+}
+
+// Helper callback that puts the TransactionResult for the expectedTxnId into a
+// promise
+class TxnResultCallback : public ContexthubCallbackV1_2 {
+  public:
+    virtual Return<void> handleTxnResult(uint32_t txnId, TransactionResult result) override {
+        ALOGD("Got transaction result callback for txnId %" PRIu32 " (expecting %" PRIu32
+              ") with result %" PRId32,
+              txnId, expectedTxnId, result);
+        if (txnId == expectedTxnId) {
+            promise.set_value(result);
+        }
+        return Void();
+    }
+
+    uint32_t expectedTxnId = 0;
+    std::promise<TransactionResult> promise;
+};
+
+// Parameterized fixture that sets the callback to TxnResultCallback
+class ContexthubTxnTest : public ContexthubHidlTest {
+  public:
+    virtual void SetUp() override {
+        ContexthubHidlTest::SetUp();
+        ASSERT_OK(registerCallback_1_2(cb));
+    }
+
+    sp<TxnResultCallback> cb = new TxnResultCallback();
+};
+
+TEST_P(ContexthubTxnTest, TestSendMessageToNonExistentNanoApp) {
+    ContextHubMsg msg;
+    msg.msg_1_0.appName = kNonExistentAppId;
+    msg.msg_1_0.msgType = 1;
+    msg.msg_1_0.msg.resize(4);
+    std::fill(msg.msg_1_0.msg.begin(), msg.msg_1_0.msg.end(), 0);
+
+    ALOGD("Sending message to non-existent nanoapp");
+    Result result = hubApi->sendMessageToHub_1_2(getHubId(), msg);
+    if (result != Result::OK && result != Result::BAD_PARAMS &&
+        result != Result::TRANSACTION_FAILED) {
+        FAIL() << "Got result " << asBaseType(result) << ", expected OK, BAD_PARAMS"
+               << ", or TRANSACTION_FAILED";
+    }
 }
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ContexthubHidlTest);
 INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubHidlTest, testing::ValuesIn(kTestParameters),
                          android::hardware::PrintInstanceTupleNameToString<>);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ContexthubTxnTest);
+INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubTxnTest, testing::ValuesIn(kTestParameters),
+                         android::hardware::PrintInstanceTupleNameToString<>);
+
 }  // anonymous namespace
diff --git a/contexthub/common/vts/ContexthubCallbackBase.h b/contexthub/common/vts/ContexthubCallbackBase.h
index 124a116..24d6c52 100644
--- a/contexthub/common/vts/ContexthubCallbackBase.h
+++ b/contexthub/common/vts/ContexthubCallbackBase.h
@@ -27,7 +27,8 @@
 
 // Base callback implementation that just logs all callbacks by default, but
 // records a failure if
-class ContexthubCallbackBase : public V1_0::IContexthubCallback {
+template <class CallbackType>
+class ContexthubCallbackBase : public CallbackType {
   public:
     virtual Return<void> handleClientMsg(const V1_0::ContextHubMsg& /*msg*/) override {
         ALOGD("Got client message callback");
diff --git a/contexthub/common/vts/VtsHalContexthubUtils.h b/contexthub/common/vts/VtsHalContexthubUtils.h
index 8f9b694..dff1865 100644
--- a/contexthub/common/vts/VtsHalContexthubUtils.h
+++ b/contexthub/common/vts/VtsHalContexthubUtils.h
@@ -30,6 +30,10 @@
 namespace contexthub {
 namespace vts_utils {
 
+// App ID with vendor "GoogT" (Google Testing), app identifier 0x555555. This
+// app ID is reserved and must never appear in the list of loaded apps.
+constexpr uint64_t kNonExistentAppId = 0x476f6f6754555555;
+
 #define ASSERT_OK(result) ASSERT_EQ(result, ::android::hardware::contexthub::V1_0::Result::OK)
 #define EXPECT_OK(result) EXPECT_EQ(result, ::android::hardware::contexthub::V1_0::Result::OK)
 
@@ -64,6 +68,29 @@
     return parameters;
 }
 
+// Wait for a callback to occur (signaled by the given future) up to the
+// provided timeout. If the future is invalid or the callback does not come
+// within the given time, returns false.
+template <class ReturnType>
+bool waitForCallback(std::future<ReturnType> future, ReturnType* result,
+                     std::chrono::milliseconds timeout = std::chrono::seconds(5)) {
+    auto expiration = std::chrono::system_clock::now() + timeout;
+
+    EXPECT_NE(result, nullptr);
+    EXPECT_TRUE(future.valid());
+    if (result != nullptr && future.valid()) {
+        std::future_status status = future.wait_until(expiration);
+        EXPECT_NE(status, std::future_status::timeout) << "Timed out waiting for callback";
+
+        if (status == std::future_status::ready) {
+            *result = future.get();
+            return true;
+        }
+    }
+
+    return false;
+}
+
 }  // namespace vts_utils
 }  // namespace contexthub
 }  // namespace hardware
diff --git a/current.txt b/current.txt
index fb9b056..5e9a34c 100644
--- a/current.txt
+++ b/current.txt
@@ -779,8 +779,9 @@
 6017b4f2481feb0fffceae81c62bc372c898998b2d8fe69fbd39859d3a315e5e android.hardware.keymaster@4.0::IKeymasterDevice
 dabe23dde7c9e3ad65c61def7392f186d7efe7f4216f9b6f9cf0863745b1a9f4 android.hardware.keymaster@4.1::IKeymasterDevice
 cd84ab19c590e0e73dd2307b591a3093ee18147ef95e6d5418644463a6620076 android.hardware.neuralnetworks@1.2::IDevice
-9625e85f56515ad2cf87b6a1847906db669f746ea4ab02cd3d4ca25abc9b0109 android.hardware.neuralnetworks@1.2::types
-9e758e208d14f7256e0885d6d8ad0b61121b21d8c313864f981727ae55bffd16 android.hardware.neuralnetworks@1.3::types
+f729ee6a5f136b25d79ea6895d24700fce413df555baaecf2c39e4440d15d043 android.hardware.neuralnetworks@1.0::types
+c6ae443608502339aec4256feef48e7b2d36f7477ca5361cc95cd27a8ed9c612 android.hardware.neuralnetworks@1.2::types
+9fe5a4093043c2b5da4e9491aed1646c388a5d3059b8fd77d5b6a9807e6d3a3e android.hardware.neuralnetworks@1.3::types
 e8c86c69c438da8d1549856c1bb3e2d1b8da52722f8235ff49a30f2cce91742c android.hardware.soundtrigger@2.1::ISoundTriggerHwCallback
 b9fbb6e2e061ed0960939d48b785e9700210add1f13ed32ecd688d0f1ca20ef7 android.hardware.renderscript@1.0::types
 0f53d70e1eadf8d987766db4bf6ae2048004682168f4cab118da576787def3fa android.hardware.radio@1.0::types
diff --git a/drm/1.4/types.hal b/drm/1.4/types.hal
index 09531a4..17eba8a 100644
--- a/drm/1.4/types.hal
+++ b/drm/1.4/types.hal
@@ -19,11 +19,14 @@
 import @1.2::Status;
 
 enum LogPriority : uint32_t {
-  ERROR,
-  WARN,
-  INFO,
-  DEBUG,
-  VERBOSE
+    UNKNOWN,
+    DEFAULT,
+    VERBOSE,
+    DEBUG,
+    INFO,
+    WARN,
+    ERROR,
+    FATAL,
 };
 
 /**
diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp
index 91985ce..6418028 100644
--- a/identity/support/src/IdentityCredentialSupport.cpp
+++ b/identity/support/src/IdentityCredentialSupport.cpp
@@ -833,9 +833,16 @@
 optional<vector<vector<uint8_t>>> createAttestation(
         const EVP_PKEY* key, const vector<uint8_t>& applicationId, const vector<uint8_t>& challenge,
         uint64_t activeTimeMilliSeconds, uint64_t expireTimeMilliSeconds, bool isTestCredential) {
+    // Pretend to be implemented in a trusted environment just so we can pass
+    // the VTS tests. Of course, this is a pretend-only game since hopefully no
+    // relying party is ever going to trust our batch key and those keys above
+    // it.
+    ::keymaster::PureSoftKeymasterContext context(::keymaster::KmVersion::KEYMASTER_4_1,
+                                                  KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT);
+
     keymaster_error_t error;
     ::keymaster::CertificateChain attestation_chain =
-            ::keymaster::getAttestationChain(KM_ALGORITHM_EC, &error);
+            context.GetAttestationChain(KM_ALGORITHM_EC, &error);
     if (KM_ERROR_OK != error) {
         LOG(ERROR) << "Error getting attestation chain " << error;
         return {};
@@ -855,12 +862,6 @@
         }
         expireTimeMilliSeconds = bcNotAfter * 1000;
     }
-    const keymaster_key_blob_t* attestation_signing_key =
-            ::keymaster::getAttestationKey(KM_ALGORITHM_EC, nullptr);
-    if (attestation_signing_key == nullptr) {
-        LOG(ERROR) << "Error getting attestation key";
-        return {};
-    }
 
     ::keymaster::X509_NAME_Ptr subjectName;
     if (KM_ERROR_OK !=
@@ -917,16 +918,8 @@
     }
     ::keymaster::AuthorizationSet hwEnforced(hwEnforcedBuilder);
 
-    // Pretend to be implemented in a trusted environment just so we can pass
-    // the VTS tests. Of course, this is a pretend-only game since hopefully no
-    // relying party is ever going to trust our batch key and those keys above
-    // it.
-    ::keymaster::PureSoftKeymasterContext context(::keymaster::KmVersion::KEYMINT_1,
-                                                  KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT);
-
-    ::keymaster::CertificateChain cert_chain_out = generate_attestation_from_EVP(
-            key, swEnforced, hwEnforced, auth_set, context, move(attestation_chain),
-            *attestation_signing_key, &error);
+    ::keymaster::CertificateChain cert_chain_out = generate_attestation(
+            key, swEnforced, hwEnforced, auth_set, {} /* attest_key */, context, &error);
 
     if (KM_ERROR_OK != error) {
         LOG(ERROR) << "Error generating attestation from EVP key: " << error;
diff --git a/memtrack/aidl/vts/Android.bp b/memtrack/aidl/vts/Android.bp
index df87db8..eff2a56 100644
--- a/memtrack/aidl/vts/Android.bp
+++ b/memtrack/aidl/vts/Android.bp
@@ -13,6 +13,6 @@
         "android.hardware.memtrack-V1-ndk_platform",
     ],
     test_suites: [
-        "vts-core",
+        "vts",
     ],
 }
diff --git a/neuralnetworks/1.0/types.hal b/neuralnetworks/1.0/types.hal
index 620eefb..5bfadd3 100644
--- a/neuralnetworks/1.0/types.hal
+++ b/neuralnetworks/1.0/types.hal
@@ -308,8 +308,9 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, out_height, out_width, depth_out].
-     *      For output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
-     *      the following condition must be satisfied: output_scale > input_scale * filter_scale
+     *      For output tensor of
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the following condition must
+     *      be satisfied: output_scale > input_scale * filter_scale
      */
     CONV_2D = 3,
 
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
index 7441a54..7cec49e 100644
--- a/neuralnetworks/1.2/types.hal
+++ b/neuralnetworks/1.2/types.hal
@@ -314,7 +314,8 @@
      *      tensors. The output shape is [D0, D1, ..., sum(Daxis(i)), ..., Dm].
      *      Since HAL version 1.2, for a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
      *      the scale and zeroPoint values can be different from
-     *      input tensors. Before HAL version 1.2 they have to be the same as for the input tensors.
+     *      input tensors. Before HAL version 1.2 they have to be the same as for the
+     *      input tensors.
      */
     CONCATENATION = @1.1::OperationType:CONCATENATION,
 
@@ -460,8 +461,9 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, out_height, out_width, depth_out].
-     *      Before HAL version 1.2, for output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
-     *      the following condition must be satisfied: output_scale > input_scale * filter_scale
+     *      Before HAL version 1.2, for output tensor of
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the following condition must
+     *      be satisfied: output_scale > input_scale * filter_scale
      */
     CONV_2D = @1.1::OperationType:CONV_2D,
 
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index 5f5ee03..51837fe 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -263,7 +263,8 @@
      *      tensors. The output shape is [D0, D1, ..., sum(Daxis(i)), ..., Dm].
      *      Since HAL version 1.2, for a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
      *      the scale and zeroPoint values can be different from
-     *      input tensors. Before HAL version 1.2 they have to be the same as for the input tensors.
+     *      input tensors. Before HAL version 1.2 they have to be the same as for the
+     *      input tensors.
      *      For a {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scale and zeroPoint values can be different from input tensors.
      */
@@ -312,7 +313,8 @@
      * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
      * * * input.scale * filter.scale).
      *
-     * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3):
+     * * Quantized signed with filter symmetric per channel quantization
+     *   (since HAL version 1.3):
      * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, and output.
      * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
      * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
@@ -425,8 +427,9 @@
      * Outputs:
      * * 0: The output 4-D tensor, of shape
      *      [batches, out_height, out_width, depth_out].
-     *      Before HAL version 1.2, for output tensor of {@link OperandType::TENSOR_QUANT8_ASYMM},
-     *      the following condition must be satisfied: output_scale > input_scale * filter_scale
+     *      Before HAL version 1.2, for output tensor of
+     *      {@link OperandType::TENSOR_QUANT8_ASYMM}, the following condition must
+     *      be satisfied: output_scale > input_scale * filter_scale
      */
     CONV_2D = @1.2::OperationType:CONV_2D,
 
@@ -477,7 +480,8 @@
      * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
      * * * input.scale * filter.scale).
      *
-     * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3):
+     * * Quantized signed with filter symmetric per channel quantization
+     *   (since HAL version 1.3):
      * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, and output.
      * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
      * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
@@ -3354,7 +3358,8 @@
      * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
      * * * each value scaling is separate and equal to input.scale * filter.scales[channel]).
      *
-     * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3):
+     * * Quantized signed with filter symmetric per channel quantization
+     *   (since HAL version 1.3):
      * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, and output.
      * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
      * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
@@ -4615,7 +4620,8 @@
      * * * {@link OperandType::TENSOR_INT32} for bias (with scale set to
      * * * input.scale * filter.scale).
      *
-     * * Quantized signed with filter symmetric per channel quantization (since HAL version 1.3):
+     * * Quantized signed with filter symmetric per channel quantization
+     *   (since HAL version 1.3):
      * * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} for input, and output.
      * * * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter.
      * * * {@link OperandType::TENSOR_INT32} for bias (scale set to 0.0,
diff --git a/neuralnetworks/TEST_MAPPING b/neuralnetworks/TEST_MAPPING
index de84624..5d168d2 100644
--- a/neuralnetworks/TEST_MAPPING
+++ b/neuralnetworks/TEST_MAPPING
@@ -60,6 +60,17 @@
           "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
         }
       ]
+    },
+    {
+      "name": "VtsHalNeuralnetworksTargetTest",
+      "options": [
+        {
+          // Do not use any sample driver except sample-all in order to reduce
+          // testing time. The other sample drivers (fast-float, quant, etc.)
+          // are subsets of sample-all.
+          "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
+        }
+      ]
     }
   ]
 }
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumer.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumer.aidl
index c8d7645..cd9239e 100644
--- a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumer.aidl
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumer.aidl
@@ -35,6 +35,6 @@
 parcelable EnergyConsumer {
   int id;
   int ordinal;
-  android.hardware.power.stats.EnergyConsumerType type;
+  android.hardware.power.stats.EnergyConsumerType type = android.hardware.power.stats.EnergyConsumerType.OTHER;
   @utf8InCpp String name;
 }
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerType.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerType.aidl
index 7b05d2f..ce3e1f5 100644
--- a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerType.aidl
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerType.aidl
@@ -34,6 +34,10 @@
 @VintfStability
 enum EnergyConsumerType {
   OTHER = 0,
-  CPU_CLUSTER = 1,
-  DISPLAY = 2,
+  BLUETOOTH = 1,
+  CPU_CLUSTER = 2,
+  DISPLAY = 3,
+  GNSS = 4,
+  MOBILE_RADIO = 5,
+  WIFI = 6,
 }
diff --git a/power/stats/aidl/android/hardware/power/stats/EnergyConsumer.aidl b/power/stats/aidl/android/hardware/power/stats/EnergyConsumer.aidl
index 2ff1279..ec616f2 100644
--- a/power/stats/aidl/android/hardware/power/stats/EnergyConsumer.aidl
+++ b/power/stats/aidl/android/hardware/power/stats/EnergyConsumer.aidl
@@ -32,10 +32,10 @@
     int ordinal;
 
     /* Type of this EnergyConsumer */
-    EnergyConsumerType type;
+    EnergyConsumerType type = EnergyConsumerType.OTHER;
 
     /**
      * Unique name of this EnergyConsumer. Vendor/device specific. Opaque to framework
      */
     @utf8InCpp String name;
-}
\ No newline at end of file
+}
diff --git a/power/stats/aidl/android/hardware/power/stats/EnergyConsumerType.aidl b/power/stats/aidl/android/hardware/power/stats/EnergyConsumerType.aidl
index 7fd2348..d871ced 100644
--- a/power/stats/aidl/android/hardware/power/stats/EnergyConsumerType.aidl
+++ b/power/stats/aidl/android/hardware/power/stats/EnergyConsumerType.aidl
@@ -20,6 +20,10 @@
 @VintfStability
 enum EnergyConsumerType {
     OTHER,
+    BLUETOOTH,
     CPU_CLUSTER,
     DISPLAY,
-}
\ No newline at end of file
+    GNSS,
+    MOBILE_RADIO,
+    WIFI,
+}
diff --git a/radio/1.6/IRadio.hal b/radio/1.6/IRadio.hal
index 7a13f0d..714be47 100644
--- a/radio/1.6/IRadio.hal
+++ b/radio/1.6/IRadio.hal
@@ -465,7 +465,7 @@
      * cell information isn't known then the appropriate unknown value will be returned.
      * This does not cause or change the rate of unsolicited cellInfoList().
      *
-     * This is identitcal to getCellInfoList in V1.0, but it requests updated version of CellInfo.
+     * This is identical to getCellInfoList in V1.0, but it requests updated version of CellInfo.
      *
      * @param serial Serial number of request.
      *
diff --git a/radio/1.6/IRadioResponse.hal b/radio/1.6/IRadioResponse.hal
index 6ad5cf2..56ce809 100644
--- a/radio/1.6/IRadioResponse.hal
+++ b/radio/1.6/IRadioResponse.hal
@@ -19,6 +19,7 @@
 import @1.0::SendSmsResult;
 import @1.4::RadioAccessFamily;
 import @1.5::IRadioResponse;
+import @1.5::RadioAccessSpecifier;
 import @1.6::Call;
 import @1.6::CellInfo;
 import @1.6::RegStateResult;
@@ -344,6 +345,7 @@
 
     /**
      * @param info Response info struct containing response type, serial no. and error
+     * @param specifiers List of RadioAccessSpecifiers that are scanned.
      *
      * Valid errors returned:
      *   RadioError:NONE
@@ -351,7 +353,8 @@
      *   RadioError:INTERNAL_ERR
      *   RadioError:INVALID_ARGUMENTS
      */
-    oneway getSystemSelectionChannelsResponse(RadioResponseInfo info);
+    oneway getSystemSelectionChannelsResponse(
+            RadioResponseInfo info, vec<RadioAccessSpecifier> specifiers);
 
     /**
      * This is identical to getCellInfoListResponse_1_5 but uses an updated version of CellInfo.
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h b/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
index f32e312..f610f2a 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
+++ b/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
@@ -805,7 +805,8 @@
             const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
 
     Return<void> getSystemSelectionChannelsResponse(
-            const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+            const hidl_vec<::android::hardware::radio::V1_5::RadioAccessSpecifier>& specifier);
 
     Return<void> getSignalStrengthResponse_1_6(
             const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
diff --git a/radio/1.6/vts/functional/radio_response.cpp b/radio/1.6/vts/functional/radio_response.cpp
index fad3f12..027e9ac 100644
--- a/radio/1.6/vts/functional/radio_response.cpp
+++ b/radio/1.6/vts/functional/radio_response.cpp
@@ -1190,7 +1190,8 @@
 }
 
 Return<void> RadioResponse_v1_6::getSystemSelectionChannelsResponse(
-        const ::android::hardware::radio::V1_6::RadioResponseInfo& info) {
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+        const hidl_vec<::android::hardware::radio::V1_5::RadioAccessSpecifier>& /*specifier*/) {
     rspInfo = info;
     parent_v1_6.notify(info.serial);
     return Void();
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/AttestationKey.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/AttestationKey.aidl
new file mode 100644
index 0000000..893b016
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/AttestationKey.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
+parcelable AttestationKey {
+  byte[] keyBlob;
+  android.hardware.security.keymint.KeyParameter[] attestKeyParams;
+  byte[] issuerSubjectName;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl
index a35b46c..3faba48 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl
@@ -113,6 +113,8 @@
   UNSUPPORTED_MGF_DIGEST = -79,
   MISSING_NOT_BEFORE = -80,
   MISSING_NOT_AFTER = -81,
+  MISSING_ISSUER_SUBJECT = -82,
+  INVALID_ISSUER_SUBJECT = -83,
   UNIMPLEMENTED = -100,
   VERSION_MISMATCH = -101,
   UNKNOWN_ERROR = -1000,
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
index 9f4e509..d3c6910 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -35,14 +35,14 @@
 interface IKeyMintDevice {
   android.hardware.security.keymint.KeyMintHardwareInfo getHardwareInfo();
   void addRngEntropy(in byte[] data);
-  android.hardware.security.keymint.KeyCreationResult generateKey(in android.hardware.security.keymint.KeyParameter[] keyParams);
-  android.hardware.security.keymint.KeyCreationResult importKey(in android.hardware.security.keymint.KeyParameter[] keyParams, in android.hardware.security.keymint.KeyFormat keyFormat, in byte[] keyData);
+  android.hardware.security.keymint.KeyCreationResult generateKey(in android.hardware.security.keymint.KeyParameter[] keyParams, in @nullable android.hardware.security.keymint.AttestationKey attestationKey);
+  android.hardware.security.keymint.KeyCreationResult importKey(in android.hardware.security.keymint.KeyParameter[] keyParams, in android.hardware.security.keymint.KeyFormat keyFormat, in byte[] keyData, in @nullable android.hardware.security.keymint.AttestationKey attestationKey);
   android.hardware.security.keymint.KeyCreationResult importWrappedKey(in byte[] wrappedKeyData, in byte[] wrappingKeyBlob, in byte[] maskingKey, in android.hardware.security.keymint.KeyParameter[] unwrappingParams, in long passwordSid, in long biometricSid);
-  byte[] upgradeKey(in byte[] inKeyBlobToUpgrade, in android.hardware.security.keymint.KeyParameter[] inUpgradeParams);
-  void deleteKey(in byte[] inKeyBlob);
+  byte[] upgradeKey(in byte[] keyBlobToUpgrade, in android.hardware.security.keymint.KeyParameter[] upgradeParams);
+  void deleteKey(in byte[] keyBlob);
   void deleteAllKeys();
   void destroyAttestationIds();
-  android.hardware.security.keymint.BeginResult begin(in android.hardware.security.keymint.KeyPurpose inPurpose, in byte[] inKeyBlob, in android.hardware.security.keymint.KeyParameter[] inParams, in android.hardware.security.keymint.HardwareAuthToken inAuthToken);
+  android.hardware.security.keymint.BeginResult begin(in android.hardware.security.keymint.KeyPurpose purpose, in byte[] keyBlob, in android.hardware.security.keymint.KeyParameter[] params, in android.hardware.security.keymint.HardwareAuthToken authToken);
   void deviceLocked(in boolean passwordOnly, in @nullable android.hardware.security.secureclock.TimeStampToken timestampToken);
   void earlyBootEnded();
   const int AUTH_TOKEN_MAC_LENGTH = 32;
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
new file mode 100644
index 0000000..a864c3c
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ *////////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@VintfStability
+interface IRemotelyProvisionedComponent {
+  byte[] generateEcdsaP256KeyPair(in boolean testMode, out android.hardware.security.keymint.MacedPublicKey macedPublicKey);
+  void generateCertificateRequest(in boolean testMode, in android.hardware.security.keymint.MacedPublicKey[] keysToSign, in byte[] endpointEncryptionCertChain, in byte[] challenge, out byte[] keysToSignMac, out android.hardware.security.keymint.ProtectedData protectedData);
+  const int STATUS_FAILED = 1;
+  const int STATUS_INVALID_MAC = 2;
+  const int STATUS_PRODUCTION_KEY_IN_TEST_REQUEST = 3;
+  const int STATUS_TEST_KEY_IN_PRODUCTION_REQUEST = 4;
+  const int STATUS_INVALID_EEK = 5;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyPurpose.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyPurpose.aidl
index c1e92af..61bb7e4 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyPurpose.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyPurpose.aidl
@@ -39,4 +39,5 @@
   VERIFY = 3,
   WRAP_KEY = 5,
   AGREE_KEY = 6,
+  ATTEST_KEY = 7,
 }
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/MacedPublicKey.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/MacedPublicKey.aidl
new file mode 100644
index 0000000..b4caeed
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/MacedPublicKey.aidl
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ *////////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@VintfStability
+parcelable MacedPublicKey {
+  byte[] macedKey;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ProtectedData.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ProtectedData.aidl
new file mode 100644
index 0000000..46f602f
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ProtectedData.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *////////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@VintfStability
+parcelable ProtectedData {
+  byte[] protectedData;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/AttestationKey.aidl b/security/keymint/aidl/android/hardware/security/keymint/AttestationKey.aidl
new file mode 100644
index 0000000..8167ceb
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/AttestationKey.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.keymint;
+
+import android.hardware.security.keymint.KeyParameter;
+
+/**
+ * Contains a key blob with Tag::ATTEST_KEY that can be used to sign an attestation certificate,
+ * and the DER-encoded X.501 Subject Name that will be placed in the Issuer field of the attestation
+ * certificate.
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable AttestationKey {
+    byte[] keyBlob;
+    KeyParameter[] attestKeyParams;
+    byte[] issuerSubjectName;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl b/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl
index 35e3827..5765130 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl
@@ -103,6 +103,8 @@
     UNSUPPORTED_MGF_DIGEST = -79,
     MISSING_NOT_BEFORE = -80,
     MISSING_NOT_AFTER = -81,
+    MISSING_ISSUER_SUBJECT = -82,
+    INVALID_ISSUER_SUBJECT = -83,
 
     UNIMPLEMENTED = -100,
     VERSION_MISMATCH = -101,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 71abedd..13e98af 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.security.keymint;
 
+import android.hardware.security.keymint.AttestationKey;
 import android.hardware.security.keymint.BeginResult;
 import android.hardware.security.keymint.ByteArray;
 import android.hardware.security.keymint.HardwareAuthToken;
@@ -315,9 +316,18 @@
      *        provided in params.  See above for detailed specifications of which tags are required
      *        for which types of keys.
      *
+     * @param attestationKey, if provided, specifies the key that must be used to sign the
+     *        attestation certificate.  If `keyParams` does not contain a Tag::ATTESTATION_CHALLENGE
+     *        but `attestationKey` is non-null, the IKeyMintDevice must return
+     *        ErrorCode::INVALID_ARGUMENT.  If the provided AttestationKey does not contain a key
+     *        blob containing an asymmetric key with KeyPurpose::ATTEST_KEY, the IKeyMintDevice must
+     *        return ErrorCode::INVALID_PURPOSE.  If the provided AttestationKey has an empty issuer
+     *        subject name, the IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT.
+     *
      * @return The result of key creation.  See KeyCreationResult.aidl.
      */
-    KeyCreationResult generateKey(in KeyParameter[] keyParams);
+    KeyCreationResult generateKey(
+            in KeyParameter[] keyParams, in @nullable AttestationKey attestationKey);
 
     /**
      * Imports key material into an IKeyMintDevice.  Key definition parameters and return values
@@ -345,10 +355,18 @@
      *
      * @param inKeyData The key material to import, in the format specified in keyFormat.
      *
+     * @param attestationKey, if provided, specifies the key that must be used to sign the
+     *        attestation certificate.  If `keyParams` does not contain a Tag::ATTESTATION_CHALLENGE
+     *        but `attestationKey` is non-null, the IKeyMintDevice must return
+     *        ErrorCode::INVALID_ARGUMENT.  If the provided AttestationKey does not contain a key
+     *        blob containing an asymmetric key with KeyPurpose::ATTEST_KEY, the IKeyMintDevice must
+     *        return ErrorCode::INVALID_PURPOSE.  If the provided AttestationKey has an empty issuer
+     *        subject name, the IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT.
+     *
      * @return The result of key creation.  See KeyCreationResult.aidl.
      */
-    KeyCreationResult importKey(
-            in KeyParameter[] keyParams, in KeyFormat keyFormat, in byte[] keyData);
+    KeyCreationResult importKey(in KeyParameter[] keyParams, in KeyFormat keyFormat,
+            in byte[] keyData, in @nullable AttestationKey attestationKey);
 
     /**
      * Securely imports a key, or key pair, returning a key blob and a description of the imported
@@ -467,7 +485,7 @@
      * @return A new key blob that references the same key as keyBlobToUpgrade, but is in the new
      *         format, or has the new version data.
      */
-    byte[] upgradeKey(in byte[] inKeyBlobToUpgrade, in KeyParameter[] inUpgradeParams);
+    byte[] upgradeKey(in byte[] keyBlobToUpgrade, in KeyParameter[] upgradeParams);
 
     /**
      * Deletes the key, or key pair, associated with the key blob.  Calling this function on
@@ -477,7 +495,7 @@
      *
      * @param inKeyBlob The opaque descriptor returned by generateKey() or importKey();
      */
-    void deleteKey(in byte[] inKeyBlob);
+    void deleteKey(in byte[] keyBlob);
 
     /**
      * Deletes all keys in the hardware keystore.  Used when keystore is reset completely.  After
@@ -703,8 +721,8 @@
      *         from operations that generate an IV or nonce, and IKeyMintOperation object pointer
      *         which is used to perform update(), finish() or abort() operations.
      */
-    BeginResult begin(in KeyPurpose inPurpose, in byte[] inKeyBlob, in KeyParameter[] inParams,
-            in HardwareAuthToken inAuthToken);
+    BeginResult begin(in KeyPurpose purpose, in byte[] keyBlob, in KeyParameter[] params,
+            in HardwareAuthToken authToken);
 
     /**
      * Called by client to notify the IKeyMintDevice that the device is now locked, and keys with
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
new file mode 100644
index 0000000..1b09e9d
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.keymint;
+
+import android.hardware.security.keymint.MacedPublicKey;
+import android.hardware.security.keymint.ProtectedData;
+
+/**
+ * An IRemotelyProvisionedComponent is a secure-side component for which certificates can be
+ * remotely provisioned. It provides an interface for generating asymmetric key pairs and then
+ * creating a CertificateRequest that contains the generated public keys, plus other information to
+ * authenticate the request origin. The CertificateRequest can be sent to a server, which can
+ * validate the request and create certificates.
+ *
+ * This interface does not provide any way to use the generated and certified key pairs. It's
+ * intended to be implemented by a HAL service that does other things with keys (e.g. Keymint).
+ *
+ * The root of trust for secure provisioning is something called the "Boot Certificate Chain", or
+ * BCC. The BCC is a chain of public key certificates, represented as COSE_Sign1 objects containing
+ * COSE_Key representations of the public keys. The "root" of the BCC is a self-signed certificate
+ * for a device-unique public key, denoted DK_pub. All public keys in the BCC are device-unique. The
+ * public key from each certificate in the chain is used to sign the next certificate in the
+ * chain. The final, "leaf" certificate contains a public key, denoted KM_pub, whose corresponding
+ * private key, denoted KM_priv, is available for use by the IRemotelyProvisionedComponent.
+ *
+ * BCC Design
+ * ==========
+ *
+ * The BCC is designed to mirror the boot stages of a device, and to prove the content and integrity
+ * of each firmware image. In a proper BCC, each boot stage hashes its own private key with the code
+ * and any relevant configuration parameters of the next stage to produce a key pair for the next
+ * stage. Each stage also uses its own private key to sign the public key of the next stage,
+ * including in the certificate the hash of the next firmware stage, then loads the next stage,
+ * passing the private key and certificate to it in a manner that does not leak the private key to
+ * later boot stages. The BCC root key pair is generated by immutable code (e.g. ROM), from a
+ * device-unique secret. After the device-unique secret is used, it must be made unavailable to any
+ * later boot stage.
+ *
+ * In this way, booting the device incrementally builds a certificate chain that (a) identifies and
+ * validates the integrity of every stage and (b) contains a set of public keys that correspond to
+ * private keys, one known to each stage. Any stage can compute the secrets of all later stages
+ * (given the necessary input), but no stage can compute the secret of any preceding stage. Updating
+ * the firmware or configuration of any stage changes the key pair of that stage, and of all
+ * subsequent stages, and no attacker who compromised the previous version of the updated firmware
+ * can know or predict the post-update key pairs.
+ *
+ * The first BCC certificate is special because its contained public key, DK_pub, will never change,
+ * making it a permanent, device-unique identifier. Although the remaining keys in the BCC are also
+ * device-unique, they are not necessarily permanent, since they can change when the device software
+ * is updated.
+ *
+ * When the provisioning server receives a message signed by KM_priv and containing a BCC that
+ * chains from DK_pub to KM_pub, it can be certain that (barring vulnerabilities in some boot
+ * stage), the CertificateRequest came from the device associated with DK_pub, running the specific
+ * software identified by the certificates in the BCC. If the server has some mechanism for knowing
+ * which the DK_pub values of "valid" devices, it can determine whether signing certificates is
+ * appropriate.
+ *
+ * Degenerate BCCs
+ * ===============
+ *
+ * While a proper BCC, as described above, reflects the complete boot sequence from boot ROM to the
+ * secure area image of the IRemotelyProvisionedComponent, it's also possible to use a "degenerate"
+ * BCC which consists only of a single, self-signed certificate containing the public key of a
+ * hardware-bound key pair. This is an appopriate solution for devices which haven't implemented
+ * everything necessary to produce a proper BCC, but can derive a unique key pair in the secure
+ * area.  In this degenerate case, DK_pub is the same as KM_pub.
+ *
+ * BCC Privacy
+ * ===========
+ *
+ * Because the BCC constitutes an unspoofable, device-unique identifier, special care is taken to
+ * prevent its availability to entities who may wish to track devices. Two precautions are taken:
+ *
+ * 1.  The BCC is never exported from the IRemotelyProvisionedComponent except in encrypted
+ *     form. The portion of the CertificateRequest that contains the BCC is encrypted using an
+ *     Endpoint Encryption Key (EEK).  The EEK is provided in the form of a certificate chain whose
+ *     root must be pre-provisioned into the secure area (hardcoding the roots into the secure area
+ *     firmware image is a recommended approach). Multiple roots may be provisioned. If the provided
+ *     EEK does not chain back to this already-known root, the IRemotelyProvisionedComponent must
+ *     reject it.
+ *
+ * 2.  Precaution 1 above ensures that only an entity with a valid EEK private key can decrypt the
+ *     BCC. To make it feasible to build a provisioning server which cannot use the BCC to track
+ *     devices, the CertificateRequest is structured so that the server can be partitioned into two
+ *     components.  The "decrypter" decrypts the BCC, verifies DK_pub and the device's right to
+ *     receive provisioned certificates, but does not see the public keys to be signed or the
+ *     resulting certificates.  The "certifier" gets informed of the results of the decrypter's
+ *     validation and sees the public keys to be signed and resulting certificates, but does not see
+ *     the BCC.
+ *
+ * Test Mode
+ * =========
+ *
+ * The IRemotelyProvisionedComponent supports a test mode, allowing the generation of test key pairs
+ * and test CertificateRequests. Test keys/requests are annotated as such, and the BCC used for test
+ * CertificateRequests must contain freshly-generated keys, not the real BCC key pairs.
+ */
+@VintfStability
+interface IRemotelyProvisionedComponent {
+    const int STATUS_FAILED = 1;
+    const int STATUS_INVALID_MAC = 2;
+    const int STATUS_PRODUCTION_KEY_IN_TEST_REQUEST = 3;
+    const int STATUS_TEST_KEY_IN_PRODUCTION_REQUEST = 4;
+    const int STATUS_INVALID_EEK = 5;
+
+    /**
+     * generateKeyPair generates a new ECDSA P-256 key pair that can be certified.  Note that this
+     * method only generates ECDSA P-256 key pairs, but the interface can be extended to add methods
+     * for generating keys for other algorithms, if necessary.
+     *
+     * @param in boolean testMode indicates whether the generated key is for testing only. Test keys
+     *        are marked (see the definition of PublicKey in the MacedPublicKey structure) to
+     *        prevent them from being confused with production keys.
+     *
+     * @param out MacedPublicKey macedPublicKey contains the public key of the generated key pair,
+     *        MACed so that generateCertificateRequest can easily verify, without the
+     *        privateKeyHandle, that the contained public key is for remote certification.
+     *
+     * @return data representing a handle to the private key. The format is implementation-defined,
+     *         but note that specific services may define a required format.
+     */
+    byte[] generateEcdsaP256KeyPair(in boolean testMode, out MacedPublicKey macedPublicKey);
+
+    /**
+     * generateCertificateRequest creates a certificate request to be sent to the provisioning
+     * server.
+     *
+     * @param in boolean testMode indicates whether the generated certificate request is for testing
+     *        only.
+     *
+     * @param in MacedPublicKey[] keysToSign contains the set of keys to certify. The
+     *        IRemotelyProvisionedComponent must validate the MACs on each key.  If any entry in the
+     *        array lacks a valid MAC, the method must return STATUS_INVALID_MAC.
+     *
+     *        If testMode is true, the keysToCertify array must contain only keys flagged as test
+     *        keys. Otherwise, the method must return STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
+     *
+     *        If testMode is false, the keysToCertify array must not contain any keys flagged as
+     *        test keys. Otherwise, the method must return STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
+     *
+     * @param in endpointEncryptionKey contains an X25519 public key which will be used to encrypt
+     *        the BCC. For flexibility, this is represented as a certificate chain, represented as a
+     *        CBOR array of COSE_Sign1 objects, ordered from root to leaf. The leaf contains the
+     *        X25519 encryption key, each other element is an Ed25519 key signing the next in the
+     *        chain. The root is self-signed.
+     *
+     *            EekChain = [ + SignedSignatureKey, SignedEek ]
+     *
+     *            SignedSignatureKey = [              // COSE_Sign1
+     *                protected: bstr .cbor {
+     *                    1 : -8,                     // Algorithm : EdDSA
+     *                },
+     *                unprotected: bstr .size 0
+     *                payload: bstr .cbor SignatureKey,
+     *                signature: bstr PureEd25519(.cbor SignatureKeySignatureInput)
+     *            ]
+     *
+     *            SignatureKey = {                    // COSE_Key
+     *                 1 : 1,                         // Key type : Octet Key Pair
+     *                 3 : -8,                        // Algorithm : EdDSA
+     *                 -1 : 6,                        // Curve : Ed25519
+     *                 -2 : bstr                      // Ed25519 public key
+     *            }
+     *
+     *            SignatureKeySignatureInput = [
+     *                context: "Signature1",
+     *                body_protected: bstr .cbor {
+     *                    1 : -8,                     // Algorithm : EdDSA
+     *                },
+     *                external_aad: bstr .size 0,
+     *                payload: bstr .cbor SignatureKey
+     *            ]
+     *
+     *            SignedEek = [                       // COSE_Sign1
+     *                protected: bstr .cbor {
+     *                    1 : -8,                     // Algorithm : EdDSA
+     *                },
+     *                unprotected: bstr .size 0
+     *                payload: bstr .cbor Eek,
+     *                signature: bstr PureEd25519(.cbor EekSignatureInput)
+     *            ]
+     *
+     *            Eek = {                             // COSE_Key
+     *                1 : 1,                          // Key type : Octet Key Pair
+     *                2 : bstr                        // KID : EEK ID
+     *                3 : -25,                        // Algorithm : ECDH-ES + HKDF-256
+     *                -1 : 4,                         // Curve : X25519
+     *                -2 : bstr                       // Ed25519 public key
+     *            }
+     *
+     *            EekSignatureInput = [
+     *                context: "Signature1",
+     *                body_protected: bstr .cbor {
+     *                    1 : -8,                     // Algorithm : EdDSA
+     *                },
+     *                external_aad: bstr .size 0,
+     *                payload: bstr .cbor Eek
+     *            ]
+     *
+     *        If the contents of endpointEncryptionKey do not match the SignedEek structure above,
+     *        the method must return STATUS_INVALID_EEK.
+     *
+     *        If testMode is true, the method must ignore the length and content of the signatures
+     *        in the chain, which implies that it must not attempt to validate the signature.
+     *
+     *        If testMode is false, the method must validate the chain signatures, and must verify
+     *        that the public key in the root certifictate is in its pre-configured set of
+     *        authorized EEK root keys. If the public key is not in the database, or if signature
+     *        verification fails, the method must return STATUS_INVALID_EEK.
+     *
+     * @param in challenge contains a byte string from the provisioning server that must be signed
+     *        by the secure area. See the description of the 'signature' output parameter for
+     *        details.
+     *
+     * @param out keysToSignMac contains the MAC of KeysToSign in the CertificateRequest
+     *        structure. Specifically, it contains:
+     *
+     *            HMAC-256(EK_mac, .cbor KeysToMacStructure)
+     *
+     *        Where EK_mac is an ephemeral MAC key, found in ProtectedData (see below).  The MACed
+     *        data is the "tag" field of a COSE_Mac0 structure like:
+     *
+     *            MacedKeys = [                            // COSE_Mac0
+     *                protected : bstr .cbor {
+     *                    1 : 5,                           // Algorithm : HMAC-256
+     *                },
+     *                unprotected : bstr .size 0,
+     *                // Payload is PublicKeys from keysToSign argument, in provided order.
+     *                payload: bstr .cbor [ * PublicKey ],
+     *                tag: bstr
+     *           ]
+     *
+     *            KeysToMacStructure = [
+     *                context : "MAC0",
+     *                protected : bstr .cbor { 1 : 5 },    // Algorithm : HMAC-256
+     *                external_aad : bstr .size 0,
+     *                // Payload is PublicKeys from keysToSign argument, in provided order.
+     *                payload : bstr .cbor [ * PublicKey ]
+     *            ]
+     *
+     * @param out ProtectedData contains the encrypted BCC and the ephemeral MAC key used to
+     *        authenticate the keysToSign (see keysToSignMac output argument).
+     */
+    void generateCertificateRequest(in boolean testMode, in MacedPublicKey[] keysToSign,
+            in byte[] endpointEncryptionCertChain, in byte[] challenge, out byte[] keysToSignMac,
+            out ProtectedData protectedData);
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
index 68c1740..978a027 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
@@ -16,12 +16,11 @@
 
 package android.hardware.security.keymint;
 
-
 /**
  * Possible purposes of a key (or pair).
  */
 @VintfStability
-@Backing(type = "int")
+@Backing(type="int")
 enum KeyPurpose {
     /* Usable with RSA, EC and AES keys. */
     ENCRYPT = 0,
@@ -42,5 +41,7 @@
     /* Key Agreement, usable with EC keys. */
     AGREE_KEY = 6,
 
-    /* TODO(seleneh) add ATTEST_KEY and their corresponding codes and tests later*/
+    /* Usable as an attestation signing key.  Keys with this purpose must not have any other
+     * purpose. */
+    ATTEST_KEY = 7,
 }
diff --git a/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl b/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
new file mode 100644
index 0000000..da85a50
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.keymint;
+
+/**
+ * MacedPublicKey contains a CBOR-encoded public key, MACed by an IRemotelyProvisionedComponent, to
+ * prove that the key pair was generated by that component.
+ */
+@VintfStability
+parcelable MacedPublicKey {
+    /**
+     * key is a COSE_Mac0 structure containing the new public key.  It's MACed by a key available
+     * only to the secure environment, as proof that the public key was generated by that
+     * environment. In CDDL, assuming the contained key is an Ed25519 public key:
+     *
+     *     MacedPublicKey = [                     // COSE_Mac0
+     *         protected: bstr .cbor { 1 : 5},    // Algorithm : HMAC-256
+     *         unprotected: bstr .size 0,
+     *         payload : bstr .cbor PublicKey,
+     *         tag : bstr HMAC-256(K_mac, MAC_structure)
+     *     ]
+     *
+     *     PublicKey = {               // COSE_Key
+     *         1 : 1,                  // Key type : octet key pair
+     *         3 : -8                  // Algorithm : EdDSA
+     *         -1 : 6,                 // Curve : Ed25519
+     *         -2 : bstr               // X coordinate, little-endian
+     *         ? -70000 : nil          // Presence indicates this is a test key.  If set, K_mac is
+     *                                 // all zeros.
+     *     },
+     *
+     *     MAC_structure = [
+     *         context : "MAC0",
+     *         protected : bstr .cbor { 1 : 5 },
+     *         external_aad : bstr .size 0,
+     *         payload : bstr .cbor PublicKey
+     *     ]
+     *
+     * if a non-Ed25519 public key were contained, the contents of the PublicKey map would change a
+     * little; see RFC 8152 for details.
+     */
+    byte[] macedKey;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl b/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
new file mode 100644
index 0000000..1ec3bf0
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.security.keymint;
+
+/**
+ * ProtectedData contains the encrypted BCC and the ephemeral MAC key used to
+ * authenticate the keysToSign (see keysToSignMac output argument).
+ */
+@VintfStability
+parcelable ProtectedData {
+    /**
+     * ProtectedData is a COSE_Encrypt structure, specified by the following CDDL
+     *
+     *     ProtectedData = [               // COSE_Encrypt
+     *         protected: bstr .cbor {
+     *             1 : 3                   // Algorithm : AES-GCM 256
+     *         },
+     *         unprotected: {
+     *             5 : bstr .size 12       // IV
+     *         },
+     *         ciphertext: bstr,           // AES-GCM-128(K, .cbor ProtectedDataPayload)
+     *         recipients : [
+     *             [                       // COSE_Recipient
+     *                 protected : bstr .cbor {
+     *                     1 : -25         // Algorithm : ECDH-ES + HKDF-256
+     *                 },
+     *                 unprotected : {
+     *                     -1 : {          // COSE_Key
+     *                         1 : 1,      // Key type : Octet Key Pair
+     *                         -1 : 4,     // Curve : X25519
+     *                         -2 : bstr   // Sender X25519 public key
+     *                     }
+     *                     4 : bstr,       // KID : EEK ID
+     *                 },
+     *                 ciphertext : nil
+     *             ]
+     *         ]
+     *     ]
+     *
+     *     K = HKDF-256(ECDH(EEK_pub, Ephemeral_priv), Context)
+     *
+     *     Context = [                     // COSE_KDF_Context
+     *         AlgorithmID : 3             // AES-GCM 256
+     *         PartyUInfo : [
+     *             identity : bstr "client"
+     *             nonce : bstr .size 0,
+     *             other : bstr            // Ephemeral pubkey
+     *         ],
+     *         PartyVInfo : [
+     *             identity : bstr "server",
+     *             nonce : bstr .size 0,
+     *             other : bstr            // EEK pubkey
+     *         ],
+     *         SuppPubInfo : [
+     *             128,                    // Output key length
+     *             protected : bstr .size 0
+     *         ]
+     *     ]
+     *
+     *     ProtectedDataPayload [
+     *         SignedMac,
+     *         Bcc,
+     *     ]
+     *
+     *     SignedMac = [                       // COSE_Sign1
+     *         bstr .cbor {                    // Protected params
+     *             1 : -8,                     // Algorithm : EdDSA
+     *         },
+     *         bstr .size 0,                   // Unprotected params
+     *         bstr .size 32,                  // MAC key
+     *         bstr PureEd25519(DK_priv, .cbor SignedMac_structure)
+     *     ]
+     *
+     *     SignedMac_structure = [
+     *         "Signature1",
+     *         bstr .cbor {                    // Protected params
+     *             1 : -8,                     // Algorithm : EdDSA
+     *         },
+     *         bstr .cbor SignedMacAad
+     *         bstr .size 32                   // MAC key
+     *     ]
+     *
+     *     SignedMacAad = [
+     *         challenge : bstr,
+     *         DeviceInfo
+     *     ]
+     *
+     *     Bcc = [
+     *         PubKey,                        // DK_pub
+     *         + BccEntry,                    // Root -> leaf (KM_pub)
+     *     ]
+     *
+     *     BccPayload = {                     // CWT
+     *         1 : tstr,                      // Issuer
+     *         2 : tstr,                      // Subject
+     *         // See the Open Profile for DICE for details on these fields.
+     *         ? -4670545 : bstr,             // Code Hash
+     *         ? -4670546 : bstr,             // Code Descriptor
+     *         ? -4670547 : bstr,             // Configuration Hash
+     *         ? -4670548 : bstr .cbor {      // Configuration Descriptor
+     *             ? -70002 : tstr,           // Component name
+     *             ? -70003 : int,            // Firmware version
+     *             ? -70004 : null,           // Resettable
+     *         },
+     *         ? -4670549 : bstr,             // Authority Hash
+     *         ? -4670550 : bstr,             // Authority Descriptor
+     *         ? -4670551 : bstr,             // Mode
+     *         -4670552 : bstr .cbor PubKey   // Subject Public Key
+     *         -4670553 : bstr                // Key Usage
+     *     }
+     *
+     *     BccEntry = [                       // COSE_Sign1
+     *         protected: bstr .cbor {
+     *             1 : -8,                    // Algorithm : EdDSA
+     *         },
+     *         unprotected: bstr .size 0,
+     *         payload: bstr .cbor BccPayload,
+     *         // First entry in the chain is signed by DK_pub, the others are each signed by their
+     *         // immediate predecessor.  See RFC 8032 for signature representation.
+     *         signature: bstr .cbor PureEd25519(SigningKey, bstr .cbor BccEntryInput)
+     *     ]
+     *
+     *     PubKey = {                         // COSE_Key
+     *         1 : 1,                         // Key type : octet key pair
+     *         3 : -8,                        // Algorithm : EdDSA
+     *         4 : 2,                         // Ops: Verify
+     *         -1 : 6,                        // Curve : Ed25519
+     *         -2 : bstr                      // X coordinate, little-endian
+     *     }
+     *
+     *     BccEntryInput = [
+     *         context: "Signature1",
+     *         protected: bstr .cbor {
+     *             1 : -8,                    // Algorithm : EdDSA
+     *         },
+     *         external_aad: bstr .size 0,
+     *         payload: bstr .cbor BccPayload
+     *     ]
+     *
+     *     DeviceInfo = {
+     *         ? "brand" : tstr,
+     *         ? "manufacturer" : tstr,
+     *         ? "product" : tstr,
+     *         ? "model" : tstr,
+     *         ? "board" : tstr,
+     *         ? "vb_state" : "green" / "yellow" / "orange",
+     *         ? "bootloader_state" : "locked" / "unlocked",
+     *         ? "os_version" : tstr,
+     *         ? "system_patch_level" : uint,        // YYYYMMDD
+     *         ? "boot_patch_level" : uint,          // YYYYMMDD
+     *         ? "vendor_patch_level" : uint,        // YYYYMMDD
+     *     }
+     */
+    byte[] protectedData;
+}
diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp
index 9b7e081..e160548 100644
--- a/security/keymint/aidl/default/Android.bp
+++ b/security/keymint/aidl/default/Android.bp
@@ -14,19 +14,45 @@
     ],
     shared_libs: [
         "android.hardware.security.keymint-V1-ndk_platform",
-        "android.hardware.security.sharedsecret-unstable-ndk_platform",
-        "android.hardware.security.secureclock-unstable-ndk_platform",
+        "android.hardware.security.sharedsecret-V1-ndk_platform",
+        "android.hardware.security.secureclock-V1-ndk_platform",
         "libbase",
         "libbinder_ndk",
-        "libcppbor",
+        "libcppbor_external",
         "libcrypto",
         "libkeymaster_portable",
         "libkeymint",
         "liblog",
         "libpuresoftkeymasterdevice",
+        "libremote_provisioner",
         "libutils",
     ],
     srcs: [
         "service.cpp",
     ],
 }
+
+cc_library {
+    name: "libremote_provisioner",
+    vendor_available: true,
+    static_libs: [
+        "libkeymint_remote_prov_support",
+    ],
+    shared_libs: [
+        "android.hardware.security.keymint-V1-ndk_platform",
+        "libbinder_ndk",
+        "libcppbor_external",
+        "libcppcose",
+        "libcrypto",
+        "libkeymaster_portable",
+        "libkeymint",
+        "liblog",
+        "libpuresoftkeymasterdevice",
+    ],
+    export_include_dirs: [
+        ".",
+    ],
+    srcs: [
+        "RemotelyProvisionedComponent.cpp",
+    ],
+}
diff --git a/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp b/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp
new file mode 100644
index 0000000..f2651fb
--- /dev/null
+++ b/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RemotelyProvisionedComponent.h"
+
+#include <assert.h>
+#include <variant>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+#include <KeyMintUtils.h>
+#include <cppcose/cppcose.h>
+#include <keymaster/keymaster_configuration.h>
+#include <remote_prov/remote_prov_utils.h>
+
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+#include <openssl/rand.h>
+#include <openssl/x509.h>
+
+namespace aidl::android::hardware::security::keymint {
+
+using ::std::string;
+using ::std::tuple;
+using ::std::unique_ptr;
+using ::std::variant;
+using ::std::vector;
+using bytevec = ::std::vector<uint8_t>;
+
+using namespace cppcose;
+using namespace keymaster;
+
+namespace {
+
+constexpr auto STATUS_FAILED = RemotelyProvisionedComponent::STATUS_FAILED;
+constexpr auto STATUS_INVALID_EEK = RemotelyProvisionedComponent::STATUS_INVALID_EEK;
+constexpr auto STATUS_INVALID_MAC = RemotelyProvisionedComponent::STATUS_INVALID_MAC;
+constexpr uint32_t kAffinePointLength = 32;
+struct AStatusDeleter {
+    void operator()(AStatus* p) { AStatus_delete(p); }
+};
+
+// TODO(swillden): Remove the dependency on AStatus stuff.  The COSE lib should use something like
+// StatusOr, but it shouldn't depend on AStatus.
+class Status {
+  public:
+    Status() {}
+    Status(int32_t errCode, const std::string& errMsg)
+        : status_(AStatus_fromServiceSpecificErrorWithMessage(errCode, errMsg.c_str())) {}
+    explicit Status(const std::string& errMsg)
+        : status_(AStatus_fromServiceSpecificErrorWithMessage(STATUS_FAILED, errMsg.c_str())) {}
+    Status(AStatus* status) : status_(status) {}
+    Status(Status&&) = default;
+    Status(const Status&) = delete;
+
+    operator ::ndk::ScopedAStatus() && { return ndk::ScopedAStatus(status_.release()); }
+
+    bool isOk() { return !status_; }
+
+    // Don't call getMessage() unless isOk() returns false;
+    const char* getMessage() const { return AStatus_getMessage(status_.get()); }
+
+  private:
+    std::unique_ptr<AStatus, AStatusDeleter> status_;
+};
+
+template <typename T>
+class StatusOr {
+  public:
+    StatusOr(AStatus* status) : status_(status) {}
+    StatusOr(Status status) : status_(std::move(status)) {}
+    StatusOr(T val) : value_(std::move(val)) {}
+
+    bool isOk() { return status_.isOk(); }
+
+    T* operator->() & {
+        assert(isOk());
+        return &value_.value();
+    }
+    T& operator*() & {
+        assert(isOk());
+        return value_.value();
+    }
+    T&& operator*() && {
+        assert(isOk());
+        return std::move(value_).value();
+    }
+
+    const char* getMessage() const {
+        assert(!isOk());
+        return status_.getMessage();
+    }
+
+    Status moveError() {
+        assert(!isOk());
+        return std::move(status_);
+    }
+
+    T moveValue() { return std::move(value_).value(); }
+
+  private:
+    Status status_;
+    std::optional<T> value_;
+};
+
+StatusOr<std::pair<bytevec /* EEK pub */, bytevec /* EEK ID */>> validateAndExtractEekPubAndId(
+        bool testMode, const bytevec& endpointEncryptionCertChain) {
+    auto [item, newPos, errMsg] = cppbor::parse(endpointEncryptionCertChain);
+
+    if (!item || !item->asArray()) {
+        return Status("Error parsing EEK chain" + errMsg);
+    }
+
+    const cppbor::Array* certArr = item->asArray();
+    bytevec lastPubKey;
+    for (int i = 0; i < certArr->size(); ++i) {
+        auto cosePubKey = verifyAndParseCoseSign1(testMode, certArr->get(i)->asArray(),
+                                                  std::move(lastPubKey), bytevec{} /* AAD */);
+        if (!cosePubKey) {
+            return Status(STATUS_INVALID_EEK,
+                          "Failed to validate EEK chain: " + cosePubKey.moveMessage());
+        }
+        lastPubKey = *std::move(cosePubKey);
+    }
+
+    auto eek = CoseKey::parseX25519(lastPubKey, true /* requireKid */);
+    if (!eek) return Status(STATUS_INVALID_EEK, "Failed to get EEK: " + eek.moveMessage());
+
+    return std::make_pair(eek->getBstrValue(CoseKey::PUBKEY_X).value(),
+                          eek->getBstrValue(CoseKey::KEY_ID).value());
+}
+
+StatusOr<bytevec /* pubkeys */> validateAndExtractPubkeys(bool testMode,
+                                                          const vector<MacedPublicKey>& keysToSign,
+                                                          const bytevec& macKey) {
+    auto pubKeysToMac = cppbor::Array();
+    for (auto& keyToSign : keysToSign) {
+        auto [macedKeyItem, _, coseMacErrMsg] = cppbor::parse(keyToSign.macedKey);
+        if (!macedKeyItem || !macedKeyItem->asArray() ||
+            macedKeyItem->asArray()->size() != kCoseMac0EntryCount) {
+            return Status("Invalid COSE_Mac0 structure");
+        }
+
+        auto protectedParms = macedKeyItem->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
+        auto unprotectedParms = macedKeyItem->asArray()->get(kCoseMac0UnprotectedParams)->asBstr();
+        auto payload = macedKeyItem->asArray()->get(kCoseMac0Payload)->asBstr();
+        auto tag = macedKeyItem->asArray()->get(kCoseMac0Tag)->asBstr();
+        if (!protectedParms || !unprotectedParms || !payload || !tag) {
+            return Status("Invalid COSE_Mac0 contents");
+        }
+
+        auto [protectedMap, __, errMsg] = cppbor::parse(protectedParms);
+        if (!protectedMap || !protectedMap->asMap()) {
+            return Status("Invalid Mac0 protected: " + errMsg);
+        }
+        auto& algo = protectedMap->asMap()->get(ALGORITHM);
+        if (!algo || !algo->asInt() || algo->asInt()->value() != HMAC_256) {
+            return Status("Unsupported Mac0 algorithm");
+        }
+
+        auto pubKey = CoseKey::parse(payload->value(), EC2, ES256, P256);
+        if (!pubKey) return Status(pubKey.moveMessage());
+
+        bool testKey = static_cast<bool>(pubKey->getMap().get(CoseKey::TEST_KEY));
+        if (testMode && !testKey) {
+            return Status(BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST,
+                          "Production key in test request");
+        } else if (!testMode && testKey) {
+            return Status(BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST,
+                          "Test key in production request");
+        }
+
+        auto macTag = generateCoseMac0Mac(macKey, {} /* external_aad */, payload->value());
+        if (!macTag) return Status(STATUS_INVALID_MAC, macTag.moveMessage());
+        if (macTag->size() != tag->value().size() ||
+            CRYPTO_memcmp(macTag->data(), tag->value().data(), macTag->size()) != 0) {
+            return Status(STATUS_INVALID_MAC, "MAC tag mismatch");
+        }
+
+        pubKeysToMac.add(pubKey->moveMap());
+    }
+
+    return pubKeysToMac.encode();
+}
+
+StatusOr<std::pair<bytevec, bytevec>> buildCosePublicKeyFromKmCert(
+        const keymaster_blob_t* km_cert) {
+    if (km_cert == nullptr) {
+        return Status(STATUS_FAILED, "km_cert is a nullptr");
+    }
+    const uint8_t* temp = km_cert->data;
+    X509* cert = d2i_X509(NULL, &temp, km_cert->data_length);
+    if (cert == nullptr) {
+        return Status(STATUS_FAILED, "d2i_X509 returned null when attempting to get the cert.");
+    }
+    EVP_PKEY* pubKey = X509_get_pubkey(cert);
+    if (pubKey == nullptr) {
+        return Status(STATUS_FAILED, "Boringssl failed to get the public key from the cert");
+    }
+    EC_KEY* ecKey = EVP_PKEY_get0_EC_KEY(pubKey);
+    if (ecKey == nullptr) {
+        return Status(STATUS_FAILED,
+                      "The key in the certificate returned from GenerateKey is not "
+                      "an EC key.");
+    }
+    const EC_POINT* jacobian_coords = EC_KEY_get0_public_key(ecKey);
+    BIGNUM x;
+    BIGNUM y;
+    BN_CTX* ctx = BN_CTX_new();
+    if (ctx == nullptr) {
+        return Status(STATUS_FAILED, "Memory allocation failure for BN_CTX");
+    }
+    if (!EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ecKey), jacobian_coords, &x, &y,
+                                             ctx)) {
+        return Status(STATUS_FAILED, "Failed to get affine coordinates");
+    }
+    bytevec x_bytestring(kAffinePointLength);
+    bytevec y_bytestring(kAffinePointLength);
+    if (BN_bn2binpad(&x, x_bytestring.data(), kAffinePointLength) != kAffinePointLength) {
+        return Status(STATUS_FAILED, "Wrote incorrect number of bytes for x coordinate");
+    }
+    if (BN_bn2binpad(&y, y_bytestring.data(), kAffinePointLength) != kAffinePointLength) {
+        return Status(STATUS_FAILED, "Wrote incorrect number of bytes for y coordinate");
+    }
+    BN_CTX_free(ctx);
+    return std::make_pair(x_bytestring, y_bytestring);
+}
+
+cppbor::Array buildCertReqRecipients(const bytevec& pubkey, const bytevec& kid) {
+    return cppbor::Array()                   // Array of recipients
+            .add(cppbor::Array()             // Recipient
+                         .add(cppbor::Map()  // Protected
+                                      .add(ALGORITHM, ECDH_ES_HKDF_256)
+                                      .canonicalize()
+                                      .encode())
+                         .add(cppbor::Map()  // Unprotected
+                                      .add(COSE_KEY, cppbor::Map()
+                                                             .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
+                                                             .add(CoseKey::CURVE, cppcose::X25519)
+                                                             .add(CoseKey::PUBKEY_X, pubkey)
+                                                             .canonicalize())
+                                      .add(KEY_ID, kid)
+                                      .canonicalize())
+                         .add(cppbor::Null()));  // No ciphertext
+}
+
+static keymaster_key_param_t kKeyMintEcdsaP256Params[] = {
+        Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN), Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC),
+        Authorization(TAG_KEY_SIZE, 256), Authorization(TAG_DIGEST, KM_DIGEST_SHA_2_256),
+        Authorization(TAG_EC_CURVE, KM_EC_CURVE_P_256), Authorization(TAG_NO_AUTH_REQUIRED),
+        // The certificate generated by KM will be discarded, these values don't matter.
+        Authorization(TAG_CERTIFICATE_NOT_BEFORE, 0), Authorization(TAG_CERTIFICATE_NOT_AFTER, 0)};
+
+}  // namespace
+
+RemotelyProvisionedComponent::RemotelyProvisionedComponent(
+        std::shared_ptr<keymint::AndroidKeyMintDevice> keymint) {
+    std::tie(devicePrivKey_, bcc_) = generateBcc();
+    impl_ = keymint->getKeymasterImpl();
+}
+
+RemotelyProvisionedComponent::~RemotelyProvisionedComponent() {}
+
+ScopedAStatus RemotelyProvisionedComponent::generateEcdsaP256KeyPair(bool testMode,
+                                                                     MacedPublicKey* macedPublicKey,
+                                                                     bytevec* privateKeyHandle) {
+    // TODO(jbires): The following should move from ->GenerateKey to ->GenerateRKPKey and everything
+    //              after the GenerateKey call should basically be moved into that new function call
+    //              as well once the issue with libcppbor in system/keymaster is sorted out
+    GenerateKeyRequest request(impl_->message_version());
+    request.key_description.Reinitialize(kKeyMintEcdsaP256Params,
+                                         array_length(kKeyMintEcdsaP256Params));
+    GenerateKeyResponse response(impl_->message_version());
+    impl_->GenerateKey(request, &response);
+    if (response.error != KM_ERROR_OK) {
+        return km_utils::kmError2ScopedAStatus(response.error);
+    }
+
+    if (response.certificate_chain.entry_count != 1) {
+        // Error: Need the single non-signed certificate with the public key in it.
+        return Status(STATUS_FAILED,
+                      "Expected to receive a single certificate from GenerateKey. Instead got: " +
+                              std::to_string(response.certificate_chain.entry_count));
+    }
+    auto affineCoords = buildCosePublicKeyFromKmCert(response.certificate_chain.begin());
+    if (!affineCoords.isOk()) return affineCoords.moveError();
+    cppbor::Map cosePublicKeyMap = cppbor::Map()
+                                           .add(CoseKey::KEY_TYPE, EC2)
+                                           .add(CoseKey::ALGORITHM, ES256)
+                                           .add(CoseKey::CURVE, cppcose::P256)
+                                           .add(CoseKey::PUBKEY_X, affineCoords->first)
+                                           .add(CoseKey::PUBKEY_Y, affineCoords->second);
+    if (testMode) {
+        cosePublicKeyMap.add(CoseKey::TEST_KEY, cppbor::Null());
+    }
+
+    bytevec cosePublicKey = cosePublicKeyMap.canonicalize().encode();
+
+    auto macedKey = constructCoseMac0(testMode ? remote_prov::kTestMacKey : macKey_,
+                                      {} /* externalAad */, cosePublicKey);
+    if (!macedKey) return Status(macedKey.moveMessage());
+
+    macedPublicKey->macedKey = macedKey->encode();
+    *privateKeyHandle = km_utils::kmBlob2vector(response.key_blob);
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemotelyProvisionedComponent::generateCertificateRequest(
+        bool testMode, const vector<MacedPublicKey>& keysToSign,
+        const bytevec& endpointEncCertChain, const bytevec& challenge, bytevec* keysToSignMac,
+        ProtectedData* protectedData) {
+    auto pubKeysToSign = validateAndExtractPubkeys(testMode, keysToSign,
+                                                   testMode ? remote_prov::kTestMacKey : macKey_);
+    if (!pubKeysToSign.isOk()) return pubKeysToSign.moveError();
+
+    bytevec ephemeralMacKey = remote_prov::randomBytes(SHA256_DIGEST_LENGTH);
+
+    auto pubKeysToSignMac = generateCoseMac0Mac(ephemeralMacKey, bytevec{}, *pubKeysToSign);
+    if (!pubKeysToSignMac) return Status(pubKeysToSignMac.moveMessage());
+    *keysToSignMac = *std::move(pubKeysToSignMac);
+
+    bytevec devicePrivKey;
+    cppbor::Array bcc;
+    if (testMode) {
+        std::tie(devicePrivKey, bcc) = generateBcc();
+    } else {
+        devicePrivKey = devicePrivKey_;
+        bcc = bcc_.clone();
+    }
+
+    auto signedMac = constructCoseSign1(devicePrivKey /* Signing key */,  //
+                                        ephemeralMacKey /* Payload */,
+                                        cppbor::Array() /* AAD */
+                                                .add(challenge)
+                                                .add(createDeviceInfo())
+                                                .encode());
+    if (!signedMac) return Status(signedMac.moveMessage());
+
+    bytevec ephemeralPrivKey(X25519_PRIVATE_KEY_LEN);
+    bytevec ephemeralPubKey(X25519_PUBLIC_VALUE_LEN);
+    X25519_keypair(ephemeralPubKey.data(), ephemeralPrivKey.data());
+
+    auto eek = validateAndExtractEekPubAndId(testMode, endpointEncCertChain);
+    if (!eek.isOk()) return eek.moveError();
+
+    auto sessionKey = x25519_HKDF_DeriveKey(ephemeralPubKey, ephemeralPrivKey, eek->first,
+                                            true /* senderIsA */);
+    if (!sessionKey) return Status(sessionKey.moveMessage());
+
+    auto coseEncrypted =
+            constructCoseEncrypt(*sessionKey, remote_prov::randomBytes(kAesGcmNonceLength),
+                                 cppbor::Array()  // payload
+                                         .add(signedMac.moveValue())
+                                         .add(std::move(bcc))
+                                         .encode(),
+                                 {},  // aad
+                                 buildCertReqRecipients(ephemeralPubKey, eek->second));
+
+    if (!coseEncrypted) return Status(coseEncrypted.moveMessage());
+    protectedData->protectedData = coseEncrypted->encode();
+
+    return ScopedAStatus::ok();
+}
+
+bytevec RemotelyProvisionedComponent::deriveBytesFromHbk(const string& context,
+                                                         size_t numBytes) const {
+    bytevec fakeHbk(32, 0);
+    bytevec result(numBytes);
+
+    // TODO(swillden): Figure out if HKDF can fail.  It doesn't seem like it should be able to,
+    // but the function does return an error code.
+    HKDF(result.data(), numBytes,               //
+         EVP_sha256(),                          //
+         fakeHbk.data(), fakeHbk.size(),        //
+         nullptr /* salt */, 0 /* salt len */,  //
+         reinterpret_cast<const uint8_t*>(context.data()), context.size());
+
+    return result;
+}
+
+bytevec RemotelyProvisionedComponent::createDeviceInfo() const {
+    return cppbor::Map().encode();
+}
+
+std::pair<bytevec /* privKey */, cppbor::Array /* BCC */>
+RemotelyProvisionedComponent::generateBcc() {
+    bytevec privKey(ED25519_PRIVATE_KEY_LEN);
+    bytevec pubKey(ED25519_PUBLIC_KEY_LEN);
+
+    ED25519_keypair(pubKey.data(), privKey.data());
+
+    auto coseKey = cppbor::Map()
+                           .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
+                           .add(CoseKey::ALGORITHM, EDDSA)
+                           .add(CoseKey::CURVE, ED25519)
+                           .add(CoseKey::KEY_OPS, VERIFY)
+                           .add(CoseKey::PUBKEY_X, pubKey)
+                           .canonicalize()
+                           .encode();
+    auto sign1Payload = cppbor::Map()
+                                .add(1 /* Issuer */, "Issuer")
+                                .add(2 /* Subject */, "Subject")
+                                .add(-4670552 /* Subject Pub Key */, coseKey)
+                                .add(-4670553 /* Key Usage */,
+                                     std::vector<uint8_t>(0x05) /* Big endian order */)
+                                .canonicalize()
+                                .encode();
+    auto coseSign1 = constructCoseSign1(privKey,       /* signing key */
+                                        cppbor::Map(), /* extra protected */
+                                        sign1Payload, {} /* AAD */);
+    assert(coseSign1);
+
+    return {privKey, cppbor::Array().add(coseKey).add(coseSign1.moveValue())};
+}
+
+}  // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/aidl/default/RemotelyProvisionedComponent.h b/security/keymint/aidl/default/RemotelyProvisionedComponent.h
new file mode 100644
index 0000000..e8d2343
--- /dev/null
+++ b/security/keymint/aidl/default/RemotelyProvisionedComponent.h
@@ -0,0 +1,57 @@
+/*
+ * 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 <AndroidKeyMintDevice.h>
+#include <aidl/android/hardware/security/keymint/BnRemotelyProvisionedComponent.h>
+#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
+#include <cppbor.h>
+#include <keymaster/UniquePtr.h>
+#include <keymaster/android_keymaster.h>
+
+namespace aidl::android::hardware::security::keymint {
+
+using ::ndk::ScopedAStatus;
+
+class RemotelyProvisionedComponent : public BnRemotelyProvisionedComponent {
+  public:
+    explicit RemotelyProvisionedComponent(std::shared_ptr<keymint::AndroidKeyMintDevice> keymint);
+    virtual ~RemotelyProvisionedComponent();
+
+    ScopedAStatus generateEcdsaP256KeyPair(bool testMode, MacedPublicKey* macedPublicKey,
+                                           std::vector<uint8_t>* privateKeyHandle) override;
+
+    ScopedAStatus generateCertificateRequest(bool testMode,
+                                             const std::vector<MacedPublicKey>& keysToSign,
+                                             const std::vector<uint8_t>& endpointEncCertChain,
+                                             const std::vector<uint8_t>& challenge,
+                                             std::vector<uint8_t>* keysToSignMac,
+                                             ProtectedData* protectedData) override;
+
+  private:
+    // TODO(swillden): Move these into an appropriate Context class.
+    std::vector<uint8_t> deriveBytesFromHbk(const std::string& context, size_t numBytes) const;
+    std::vector<uint8_t> createDeviceInfo() const;
+    std::pair<std::vector<uint8_t>, cppbor::Array> generateBcc();
+
+    std::vector<uint8_t> macKey_ = deriveBytesFromHbk("Key to MAC public keys", 32);
+    std::vector<uint8_t> devicePrivKey_;
+    cppbor::Array bcc_;
+    std::shared_ptr<::keymaster::AndroidKeymaster> impl_;
+};
+
+}  // namespace aidl::android::hardware::security::keymint
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 73d15a8..4aa05ef 100644
--- a/security/keymint/aidl/default/android.hardware.security.keymint-service.xml
+++ b/security/keymint/aidl/default/android.hardware.security.keymint-service.xml
@@ -3,4 +3,8 @@
         <name>android.hardware.security.keymint</name>
         <fqname>IKeyMintDevice/default</fqname>
     </hal>
+    <hal format="aidl">
+        <name>android.hardware.security.keymint</name>
+        <fqname>IRemotelyProvisionedComponent/default</fqname>
+    </hal>
 </manifest>
diff --git a/security/keymint/aidl/default/service.cpp b/security/keymint/aidl/default/service.cpp
index 75b394e..bcebbaf 100644
--- a/security/keymint/aidl/default/service.cpp
+++ b/security/keymint/aidl/default/service.cpp
@@ -25,7 +25,10 @@
 #include <AndroidSharedSecret.h>
 #include <keymaster/soft_keymaster_logger.h>
 
+#include "RemotelyProvisionedComponent.h"
+
 using aidl::android::hardware::security::keymint::AndroidKeyMintDevice;
+using aidl::android::hardware::security::keymint::RemotelyProvisionedComponent;
 using aidl::android::hardware::security::keymint::SecurityLevel;
 using aidl::android::hardware::security::secureclock::AndroidSecureClock;
 using aidl::android::hardware::security::sharedsecret::AndroidSharedSecret;
@@ -45,7 +48,6 @@
     // Zero threads seems like a useless pool, but below we'll join this thread to it, increasing
     // the pool size to 1.
     ABinderProcess_setThreadPoolMaxThreadCount(0);
-
     // Add Keymint Service
     std::shared_ptr<AndroidKeyMintDevice> keyMint =
             addService<AndroidKeyMintDevice>(SecurityLevel::SOFTWARE);
@@ -53,6 +55,8 @@
     addService<AndroidSecureClock>(keyMint);
     // Add Shared Secret Service
     addService<AndroidSharedSecret>(keyMint);
+    // Add Remotely Provisioned Component Service
+    addService<RemotelyProvisionedComponent>(keyMint);
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reach
 }
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index f4ba9e7..24fe616 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -21,6 +21,7 @@
         "use_libaidlvintf_gtest_helper_static",
     ],
     srcs: [
+        "AttestKeyTest.cpp",
         "KeyMintTest.cpp",
     ],
     shared_libs: [
@@ -62,6 +63,36 @@
     static_libs: [
         "android.hardware.security.keymint-V1-ndk_platform",
         "android.hardware.security.secureclock-V1-ndk_platform",
-        "libcppbor",
+        "libcppbor_external",
+    ],
+}
+
+cc_test {
+    name: "VtsHalRemotelyProvisionedComponentTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "VtsRemotelyProvisionedComponentTests.cpp",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcppbor_external",
+        "libcrypto",
+        "libkeymaster_portable",
+        "libpuresoftkeymasterdevice",
+    ],
+    static_libs: [
+        "android.hardware.security.keymint-V1-ndk_platform",
+        "libcppcose",
+        "libgmock_ndk",
+        "libremote_provisioner",
+        "libkeymint",
+        "libkeymint_remote_prov_support",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
     ],
 }
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
new file mode 100644
index 0000000..7e7a466
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "keymint_1_attest_key_test"
+#include <cutils/log.h>
+
+#include <keymint_support/key_param_output.h>
+#include <keymint_support/openssl_utils.h>
+
+#include "KeyMintAidlTestBase.h"
+
+namespace aidl::android::hardware::security::keymint::test {
+
+namespace {
+
+vector<uint8_t> make_name_from_str(const string& name) {
+    X509_NAME_Ptr x509_name(X509_NAME_new());
+    EXPECT_TRUE(x509_name.get() != nullptr);
+    if (!x509_name) return {};
+
+    EXPECT_EQ(1, X509_NAME_add_entry_by_txt(x509_name.get(),  //
+                                            "CN",             //
+                                            MBSTRING_ASC,
+                                            reinterpret_cast<const uint8_t*>(name.c_str()),
+                                            -1,  // len
+                                            -1,  // loc
+                                            0 /* set */));
+
+    int len = i2d_X509_NAME(x509_name.get(), nullptr /* only return length */);
+    EXPECT_GT(len, 0);
+
+    vector<uint8_t> retval(len);
+    uint8_t* p = retval.data();
+    i2d_X509_NAME(x509_name.get(), &p);
+
+    return retval;
+}
+
+bool IsSelfSigned(const vector<Certificate>& chain) {
+    if (chain.size() != 1) return false;
+    return ChainSignaturesAreValid(chain);
+}
+
+}  // namespace
+
+using AttestKeyTest = KeyMintAidlTestBase;
+
+TEST_P(AttestKeyTest, AllRsaSizes) {
+    for (auto size : ValidKeySizes(Algorithm::RSA)) {
+        /*
+         * Create attestaton key.
+         */
+        AttestationKey attest_key;
+        vector<KeyCharacteristics> attest_key_characteristics;
+        vector<Certificate> attest_key_cert_chain;
+        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                     .RsaSigningKey(size, 65537)
+                                                     .AttestKey()
+                                                     .SetDefaultValidity(),
+                                             {} /* attestation signing key */, &attest_key.keyBlob,
+                                             &attest_key_characteristics, &attest_key_cert_chain));
+
+        EXPECT_EQ(attest_key_cert_chain.size(), 1);
+        EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain)) << "Failed on size " << size;
+
+        /*
+         * Use attestation key to sign RSA key
+         */
+        attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+        vector<uint8_t> attested_key_blob;
+        vector<KeyCharacteristics> attested_key_characteristics;
+        vector<Certificate> attested_key_cert_chain;
+        EXPECT_EQ(ErrorCode::OK,
+                  GenerateKey(AuthorizationSetBuilder()
+                                      .RsaSigningKey(2048, 65537)
+                                      .Authorization(TAG_NO_AUTH_REQUIRED)
+                                      .AttestationChallenge("foo")
+                                      .AttestationApplicationId("bar")
+                                      .SetDefaultValidity(),
+                              attest_key, &attested_key_blob, &attested_key_characteristics,
+                              &attested_key_cert_chain));
+
+        CheckedDeleteKey(&attested_key_blob);
+
+        AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+        AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+        EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+                                              attested_key_cert_chain[0].encodedCertificate));
+
+        // Attestation by itself is not valid (last entry is not self-signed).
+        EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+        // Appending the attest_key chain to the attested_key_chain should yield a valid chain.
+        if (attest_key_cert_chain.size() > 0) {
+            attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
+        }
+        EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+        /*
+         * Use attestation key to sign EC key
+         */
+        EXPECT_EQ(ErrorCode::OK,
+                  GenerateKey(AuthorizationSetBuilder()
+                                      .EcdsaSigningKey(EcCurve::P_256)
+                                      .Authorization(TAG_NO_AUTH_REQUIRED)
+                                      .AttestationChallenge("foo")
+                                      .AttestationApplicationId("bar")
+                                      .SetDefaultValidity(),
+                              attest_key, &attested_key_blob, &attested_key_characteristics,
+                              &attested_key_cert_chain));
+
+        CheckedDeleteKey(&attested_key_blob);
+        CheckedDeleteKey(&attest_key.keyBlob);
+
+        hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+        sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+        EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+                                              attested_key_cert_chain[0].encodedCertificate));
+
+        // Attestation by itself is not valid (last entry is not self-signed).
+        EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+        // Appending the attest_key chain to the attested_key_chain should yield a valid chain.
+        if (attest_key_cert_chain.size() > 0) {
+            attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
+        }
+        EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+        // Bail early if anything failed.
+        if (HasFailure()) return;
+    }
+}
+
+TEST_P(AttestKeyTest, AllEcCurves) {
+    for (auto curve : ValidCurves()) {
+        /*
+         * Create attestaton key.
+         */
+        AttestationKey attest_key;
+        vector<KeyCharacteristics> attest_key_characteristics;
+        vector<Certificate> attest_key_cert_chain;
+        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                     .EcdsaSigningKey(curve)
+                                                     .AttestKey()
+                                                     .SetDefaultValidity(),
+                                             {} /* attestation siging key */, &attest_key.keyBlob,
+                                             &attest_key_characteristics, &attest_key_cert_chain));
+
+        EXPECT_EQ(attest_key_cert_chain.size(), 1);
+        EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain)) << "Failed on curve " << curve;
+
+        /*
+         * Use attestation key to sign RSA key
+         */
+        attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+        vector<uint8_t> attested_key_blob;
+        vector<KeyCharacteristics> attested_key_characteristics;
+        vector<Certificate> attested_key_cert_chain;
+        EXPECT_EQ(ErrorCode::OK,
+                  GenerateKey(AuthorizationSetBuilder()
+                                      .RsaSigningKey(2048, 65537)
+                                      .Authorization(TAG_NO_AUTH_REQUIRED)
+                                      .AttestationChallenge("foo")
+                                      .AttestationApplicationId("bar")
+                                      .SetDefaultValidity(),
+                              attest_key, &attested_key_blob, &attested_key_characteristics,
+                              &attested_key_cert_chain));
+
+        CheckedDeleteKey(&attested_key_blob);
+
+        AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+        AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+        EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+                                              attested_key_cert_chain[0].encodedCertificate));
+
+        // Attestation by itself is not valid (last entry is not self-signed).
+        EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+        // Appending the attest_key chain to the attested_key_chain should yield a valid chain.
+        if (attest_key_cert_chain.size() > 0) {
+            attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
+        }
+        EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+        /*
+         * Use attestation key to sign EC key
+         */
+        EXPECT_EQ(ErrorCode::OK,
+                  GenerateKey(AuthorizationSetBuilder()
+                                      .EcdsaSigningKey(EcCurve::P_256)
+                                      .Authorization(TAG_NO_AUTH_REQUIRED)
+                                      .AttestationChallenge("foo")
+                                      .AttestationApplicationId("bar")
+                                      .SetDefaultValidity(),
+                              attest_key, &attested_key_blob, &attested_key_characteristics,
+                              &attested_key_cert_chain));
+
+        CheckedDeleteKey(&attested_key_blob);
+        CheckedDeleteKey(&attest_key.keyBlob);
+
+        hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+        sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+        EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+                                              attested_key_cert_chain[0].encodedCertificate));
+
+        // Attestation by itself is not valid (last entry is not self-signed).
+        EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+        // Appending the attest_key chain to the attested_key_chain should yield a valid chain.
+        if (attest_key_cert_chain.size() > 0) {
+            attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
+        }
+        EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+        // Bail early if anything failed.
+        if (HasFailure()) return;
+    }
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(AttestKeyTest);
+
+}  // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index eb66aca..d61a081 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -22,15 +22,23 @@
 
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
+#include <cutils/properties.h>
+#include <openssl/mem.h>
 
+#include <keymint_support/attestation_record.h>
 #include <keymint_support/key_param_output.h>
 #include <keymint_support/keymint_utils.h>
+#include <keymint_support/openssl_utils.h>
 
 namespace aidl::android::hardware::security::keymint {
 
 using namespace std::literals::chrono_literals;
 using std::endl;
 using std::optional;
+using std::unique_ptr;
+using ::testing::AssertionFailure;
+using ::testing::AssertionResult;
+using ::testing::AssertionSuccess;
 
 ::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set) {
     if (set.size() == 0)
@@ -73,8 +81,67 @@
     return true;
 }
 
+// Extract attestation record from cert. Returned object is still part of cert; don't free it
+// separately.
+ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
+    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+    EXPECT_TRUE(!!oid.get());
+    if (!oid.get()) return nullptr;
+
+    int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
+    EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
+    if (location == -1) return nullptr;
+
+    X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
+    EXPECT_TRUE(!!attest_rec_ext)
+            << "Found attestation extension but couldn't retrieve it?  Probably a BoringSSL bug.";
+    if (!attest_rec_ext) return nullptr;
+
+    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+    EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
+    return attest_rec;
+}
+
+bool avb_verification_enabled() {
+    char value[PROPERTY_VALUE_MAX];
+    return property_get("ro.boot.vbmeta.device_state", value, "") != 0;
+}
+
+char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+                       '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+// Attestations don't contain everything in key authorization lists, so we need to filter the key
+// lists to produce the lists that we expect to match the attestations.
+auto kTagsToFilter = {
+        Tag::BLOB_USAGE_REQUIREMENTS,  //
+        Tag::CREATION_DATETIME,        //
+        Tag::EC_CURVE,
+        Tag::HARDWARE_TYPE,
+        Tag::INCLUDE_UNIQUE_ID,
+};
+
+AuthorizationSet filtered_tags(const AuthorizationSet& set) {
+    AuthorizationSet filtered;
+    std::remove_copy_if(
+            set.begin(), set.end(), std::back_inserter(filtered), [](const auto& entry) -> bool {
+                return std::find(kTagsToFilter.begin(), kTagsToFilter.end(), entry.tag) !=
+                       kTagsToFilter.end();
+            });
+    return filtered;
+}
+
+string x509NameToStr(X509_NAME* name) {
+    char* s = X509_NAME_oneline(name, nullptr, 0);
+    string retval(s);
+    OPENSSL_free(s);
+    return retval;
+}
+
 }  // namespace
 
+bool KeyMintAidlTestBase::arm_deleteAllKeys = false;
+bool KeyMintAidlTestBase::dump_Attestations = false;
+
 ErrorCode KeyMintAidlTestBase::GetReturnErrorCode(const Status& result) {
     if (result.isOk()) return ErrorCode::OK;
 
@@ -110,48 +177,48 @@
 }
 
 ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc,
+                                           const optional<AttestationKey>& attest_key,
                                            vector<uint8_t>* key_blob,
-                                           vector<KeyCharacteristics>* key_characteristics) {
+                                           vector<KeyCharacteristics>* key_characteristics,
+                                           vector<Certificate>* cert_chain) {
     EXPECT_NE(key_blob, nullptr) << "Key blob pointer must not be null.  Test bug";
     EXPECT_NE(key_characteristics, nullptr)
             << "Previous characteristics not deleted before generating key.  Test bug.";
 
-    // Aidl does not clear these output parameters if the function returns
-    // error.  This is different from hal where output parameter is always
-    // cleared due to hal returning void.  So now we need to do our own clearing
-    // of the output variables prior to calling keyMint aidl libraries.
-    key_blob->clear();
-    key_characteristics->clear();
-    cert_chain_.clear();
-
     KeyCreationResult creationResult;
-    Status result = keymint_->generateKey(key_desc.vector_data(), &creationResult);
-
+    Status result = keymint_->generateKey(key_desc.vector_data(), attest_key, &creationResult);
     if (result.isOk()) {
         EXPECT_PRED2(KeyCharacteristicsBasicallyValid, SecLevel(),
                      creationResult.keyCharacteristics);
         EXPECT_GT(creationResult.keyBlob.size(), 0);
         *key_blob = std::move(creationResult.keyBlob);
         *key_characteristics = std::move(creationResult.keyCharacteristics);
-        cert_chain_ = std::move(creationResult.certificateChain);
+        *cert_chain = std::move(creationResult.certificateChain);
 
         auto algorithm = key_desc.GetTagValue(TAG_ALGORITHM);
         EXPECT_TRUE(algorithm);
         if (algorithm &&
             (algorithm.value() == Algorithm::RSA || algorithm.value() == Algorithm::EC)) {
-            EXPECT_GE(cert_chain_.size(), 1);
-            if (key_desc.Contains(TAG_ATTESTATION_CHALLENGE)) EXPECT_GT(cert_chain_.size(), 1);
+            EXPECT_GE(cert_chain->size(), 1);
+            if (key_desc.Contains(TAG_ATTESTATION_CHALLENGE)) {
+                if (attest_key) {
+                    EXPECT_EQ(cert_chain->size(), 1);
+                } else {
+                    EXPECT_GT(cert_chain->size(), 1);
+                }
+            }
         } else {
             // For symmetric keys there should be no certificates.
-            EXPECT_EQ(cert_chain_.size(), 0);
+            EXPECT_EQ(cert_chain->size(), 0);
         }
     }
 
     return GetReturnErrorCode(result);
 }
 
-ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc) {
-    return GenerateKey(key_desc, &key_blob_, &key_characteristics_);
+ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc,
+                                           const optional<AttestationKey>& attest_key) {
+    return GenerateKey(key_desc, attest_key, &key_blob_, &key_characteristics_, &cert_chain_);
 }
 
 ErrorCode KeyMintAidlTestBase::ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
@@ -166,7 +233,7 @@
     KeyCreationResult creationResult;
     result = keymint_->importKey(key_desc.vector_data(), format,
                                  vector<uint8_t>(key_material.begin(), key_material.end()),
-                                 &creationResult);
+                                 {} /* attestationSigningKeyBlob */, &creationResult);
 
     if (result.isOk()) {
         EXPECT_PRED2(KeyCharacteristicsBasicallyValid, SecLevel(),
@@ -916,6 +983,240 @@
     return result;
 }
 
+bool verify_attestation_record(const string& challenge,                //
+                               const string& app_id,                   //
+                               AuthorizationSet expected_sw_enforced,  //
+                               AuthorizationSet expected_hw_enforced,  //
+                               SecurityLevel security_level,
+                               const vector<uint8_t>& attestation_cert) {
+    X509_Ptr cert(parse_cert_blob(attestation_cert));
+    EXPECT_TRUE(!!cert.get());
+    if (!cert.get()) return false;
+
+    ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
+    EXPECT_TRUE(!!attest_rec);
+    if (!attest_rec) return false;
+
+    AuthorizationSet att_sw_enforced;
+    AuthorizationSet att_hw_enforced;
+    uint32_t att_attestation_version;
+    uint32_t att_keymaster_version;
+    SecurityLevel att_attestation_security_level;
+    SecurityLevel att_keymaster_security_level;
+    vector<uint8_t> att_challenge;
+    vector<uint8_t> att_unique_id;
+    vector<uint8_t> att_app_id;
+
+    auto error = parse_attestation_record(attest_rec->data,                 //
+                                          attest_rec->length,               //
+                                          &att_attestation_version,         //
+                                          &att_attestation_security_level,  //
+                                          &att_keymaster_version,           //
+                                          &att_keymaster_security_level,    //
+                                          &att_challenge,                   //
+                                          &att_sw_enforced,                 //
+                                          &att_hw_enforced,                 //
+                                          &att_unique_id);
+    EXPECT_EQ(ErrorCode::OK, error);
+    if (error != ErrorCode::OK) return false;
+
+    EXPECT_GE(att_attestation_version, 3U);
+
+    expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID,
+                                   vector<uint8_t>(app_id.begin(), app_id.end()));
+
+    EXPECT_GE(att_keymaster_version, 4U);
+    EXPECT_EQ(security_level, att_keymaster_security_level);
+    EXPECT_EQ(security_level, att_attestation_security_level);
+
+    EXPECT_EQ(challenge.length(), att_challenge.size());
+    EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
+
+    char property_value[PROPERTY_VALUE_MAX] = {};
+    // TODO(b/136282179): When running under VTS-on-GSI the TEE-backed
+    // keymaster implementation will report YYYYMM dates instead of YYYYMMDD
+    // for the BOOT_PATCH_LEVEL.
+    if (avb_verification_enabled()) {
+        for (int i = 0; i < att_hw_enforced.size(); i++) {
+            if (att_hw_enforced[i].tag == TAG_BOOT_PATCHLEVEL ||
+                att_hw_enforced[i].tag == TAG_VENDOR_PATCHLEVEL) {
+                std::string date =
+                        std::to_string(att_hw_enforced[i].value.get<KeyParameterValue::dateTime>());
+                // strptime seems to require delimiters, but the tag value will
+                // be YYYYMMDD
+                date.insert(6, "-");
+                date.insert(4, "-");
+                EXPECT_EQ(date.size(), 10);
+                struct tm time;
+                strptime(date.c_str(), "%Y-%m-%d", &time);
+
+                // Day of the month (0-31)
+                EXPECT_GE(time.tm_mday, 0);
+                EXPECT_LT(time.tm_mday, 32);
+                // Months since Jan (0-11)
+                EXPECT_GE(time.tm_mon, 0);
+                EXPECT_LT(time.tm_mon, 12);
+                // Years since 1900
+                EXPECT_GT(time.tm_year, 110);
+                EXPECT_LT(time.tm_year, 200);
+            }
+        }
+    }
+
+    // Check to make sure boolean values are properly encoded. Presence of a boolean tag
+    // indicates true. A provided boolean tag that can be pulled back out of the certificate
+    // indicates correct encoding. No need to check if it's in both lists, since the
+    // AuthorizationSet compare below will handle mismatches of tags.
+    if (security_level == SecurityLevel::SOFTWARE) {
+        EXPECT_TRUE(expected_sw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+    } else {
+        EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+    }
+
+    // Alternatively this checks the opposite - a false boolean tag (one that isn't provided in
+    // the authorization list during key generation) isn't being attested to in the certificate.
+    EXPECT_FALSE(expected_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
+    EXPECT_FALSE(att_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
+    EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
+    EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
+
+    if (att_hw_enforced.Contains(TAG_ALGORITHM, Algorithm::EC)) {
+        // For ECDSA keys, either an EC_CURVE or a KEY_SIZE can be specified, but one must be.
+        EXPECT_TRUE(att_hw_enforced.Contains(TAG_EC_CURVE) ||
+                    att_hw_enforced.Contains(TAG_KEY_SIZE));
+    }
+
+    // Test root of trust elements
+    vector<uint8_t> verified_boot_key;
+    VerifiedBoot verified_boot_state;
+    bool device_locked;
+    vector<uint8_t> verified_boot_hash;
+    error = parse_root_of_trust(attest_rec->data, attest_rec->length, &verified_boot_key,
+                                &verified_boot_state, &device_locked, &verified_boot_hash);
+    EXPECT_EQ(ErrorCode::OK, error);
+
+    if (avb_verification_enabled()) {
+        EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
+        string prop_string(property_value);
+        EXPECT_EQ(prop_string.size(), 64);
+        EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
+
+        EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
+        if (!strcmp(property_value, "unlocked")) {
+            EXPECT_FALSE(device_locked);
+        } else {
+            EXPECT_TRUE(device_locked);
+        }
+
+        // Check that the device is locked if not debuggable, e.g., user build
+        // images in CTS. For VTS, debuggable images are used to allow adb root
+        // and the device is unlocked.
+        if (!property_get_bool("ro.debuggable", false)) {
+            EXPECT_TRUE(device_locked);
+        } else {
+            EXPECT_FALSE(device_locked);
+        }
+    }
+
+    // Verified boot key should be all 0's if the boot state is not verified or self signed
+    std::string empty_boot_key(32, '\0');
+    std::string verified_boot_key_str((const char*)verified_boot_key.data(),
+                                      verified_boot_key.size());
+    EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
+    if (!strcmp(property_value, "green")) {
+        EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
+        EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+                            verified_boot_key.size()));
+    } else if (!strcmp(property_value, "yellow")) {
+        EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED);
+        EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+                            verified_boot_key.size()));
+    } else if (!strcmp(property_value, "orange")) {
+        EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
+        EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+                            verified_boot_key.size()));
+    } else if (!strcmp(property_value, "red")) {
+        EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED);
+    } else {
+        EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
+        EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+                            verified_boot_key.size()));
+    }
+
+    att_sw_enforced.Sort();
+    expected_sw_enforced.Sort();
+    auto a = filtered_tags(expected_sw_enforced);
+    auto b = filtered_tags(att_sw_enforced);
+    EXPECT_EQ(a, b);
+
+    att_hw_enforced.Sort();
+    expected_hw_enforced.Sort();
+    EXPECT_EQ(filtered_tags(expected_hw_enforced), filtered_tags(att_hw_enforced));
+
+    return true;
+}
+
+string bin2hex(const vector<uint8_t>& data) {
+    string retval;
+    retval.reserve(data.size() * 2 + 1);
+    for (uint8_t byte : data) {
+        retval.push_back(nibble2hex[0x0F & (byte >> 4)]);
+        retval.push_back(nibble2hex[0x0F & byte]);
+    }
+    return retval;
+}
+
+AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain) {
+    std::stringstream cert_data;
+
+    for (size_t i = 0; i < chain.size(); ++i) {
+        cert_data << bin2hex(chain[i].encodedCertificate) << std::endl;
+
+        X509_Ptr key_cert(parse_cert_blob(chain[i].encodedCertificate));
+        X509_Ptr signing_cert;
+        if (i < chain.size() - 1) {
+            signing_cert = parse_cert_blob(chain[i + 1].encodedCertificate);
+        } else {
+            signing_cert = parse_cert_blob(chain[i].encodedCertificate);
+        }
+        if (!key_cert.get() || !signing_cert.get()) return AssertionFailure() << cert_data.str();
+
+        EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
+        if (!signing_pubkey.get()) return AssertionFailure() << cert_data.str();
+
+        if (!X509_verify(key_cert.get(), signing_pubkey.get())) {
+            return AssertionFailure()
+                   << "Verification of certificate " << i << " failed "
+                   << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL) << '\n'
+                   << cert_data.str();
+        }
+
+        string cert_issuer = x509NameToStr(X509_get_issuer_name(key_cert.get()));
+        string signer_subj = x509NameToStr(X509_get_subject_name(signing_cert.get()));
+        if (cert_issuer != signer_subj) {
+            return AssertionFailure() << "Cert " << i << " has wrong issuer.\n" << cert_data.str();
+        }
+
+        if (i == 0) {
+            string cert_sub = x509NameToStr(X509_get_subject_name(key_cert.get()));
+            if ("/CN=Android Keystore Key" != cert_sub) {
+                return AssertionFailure()
+                       << "Leaf cert has wrong subject, should be CN=Android Keystore Key, was "
+                       << cert_sub << '\n'
+                       << cert_data.str();
+            }
+        }
+    }
+
+    if (KeyMintAidlTestBase::dump_Attestations) std::cout << cert_data.str();
+    return AssertionSuccess();
+}
+
+X509_Ptr parse_cert_blob(const vector<uint8_t>& blob) {
+    const uint8_t* p = blob.data();
+    return X509_Ptr(d2i_X509(nullptr /* allocate new */, &p, blob.size()));
+}
+
 }  // namespace test
 
 }  // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 4e546ed..452d2b6 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -21,20 +21,27 @@
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <gtest/gtest.h>
+#include <openssl/x509.h>
 
 #include <aidl/android/hardware/security/keymint/ErrorCode.h>
 #include <aidl/android/hardware/security/keymint/IKeyMintDevice.h>
 
 #include <keymint_support/authorization_set.h>
+#include <keymint_support/openssl_utils.h>
 
 namespace aidl::android::hardware::security::keymint {
 
 ::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set);
 
+inline bool operator==(const keymint::AuthorizationSet& a, const keymint::AuthorizationSet& b) {
+    return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
+}
+
 namespace test {
 
 using ::android::sp;
 using Status = ::ndk::ScopedAStatus;
+using ::std::optional;
 using ::std::shared_ptr;
 using ::std::string;
 using ::std::vector;
@@ -48,6 +55,9 @@
         vector<KeyCharacteristics> characteristics;
     };
 
+    static bool arm_deleteAllKeys;
+    static bool dump_Attestations;
+
     void SetUp() override;
     void TearDown() override {
         if (key_blob_.size()) {
@@ -62,10 +72,19 @@
     uint32_t os_patch_level() { return os_patch_level_; }
 
     ErrorCode GetReturnErrorCode(const Status& result);
-    ErrorCode GenerateKey(const AuthorizationSet& key_desc, vector<uint8_t>* key_blob,
-                          vector<KeyCharacteristics>* key_characteristics);
 
-    ErrorCode GenerateKey(const AuthorizationSet& key_desc);
+    ErrorCode GenerateKey(const AuthorizationSet& key_desc, vector<uint8_t>* key_blob,
+                          vector<KeyCharacteristics>* key_characteristics) {
+        return GenerateKey(key_desc, std::nullopt /* attest_key */, key_blob, key_characteristics,
+                           &cert_chain_);
+    }
+    ErrorCode GenerateKey(const AuthorizationSet& key_desc,
+                          const optional<AttestationKey>& attest_key, vector<uint8_t>* key_blob,
+                          vector<KeyCharacteristics>* key_characteristics,
+                          vector<Certificate>* cert_chain);
+    ErrorCode GenerateKey(const AuthorizationSet& key_desc,
+                          const optional<AttestationKey>& attest_key = std::nullopt);
+
     ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
                         const string& key_material, vector<uint8_t>* key_blob,
                         vector<KeyCharacteristics>* key_characteristics);
@@ -254,6 +273,16 @@
     long challenge_;
 };
 
+bool verify_attestation_record(const string& challenge,                //
+                               const string& app_id,                   //
+                               AuthorizationSet expected_sw_enforced,  //
+                               AuthorizationSet expected_hw_enforced,  //
+                               SecurityLevel security_level,
+                               const vector<uint8_t>& attestation_cert);
+string bin2hex(const vector<uint8_t>& data);
+X509_Ptr parse_cert_blob(const vector<uint8_t>& blob);
+::testing::AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain);
+
 #define INSTANTIATE_KEYMINT_AIDL_TEST(name)                                          \
     INSTANTIATE_TEST_SUITE_P(PerInstance, name,                                      \
                              testing::ValuesIn(KeyMintAidlTestBase::build_params()), \
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 7801ed1..71aae90 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "keymint_5_test"
+#define LOG_TAG "keymint_1_test"
 #include <cutils/log.h>
 
 #include <signal.h>
@@ -23,34 +23,21 @@
 #include <openssl/ec.h>
 #include <openssl/evp.h>
 #include <openssl/mem.h>
-#include <openssl/x509.h>
 #include <openssl/x509v3.h>
 
 #include <cutils/properties.h>
 
 #include <aidl/android/hardware/security/keymint/KeyFormat.h>
 
-#include <keymint_support/attestation_record.h>
 #include <keymint_support/key_param_output.h>
 #include <keymint_support/openssl_utils.h>
 
 #include "KeyMintAidlTestBase.h"
 
-static bool arm_deleteAllKeys = false;
-static bool dump_Attestations = false;
-
 using aidl::android::hardware::security::keymint::AuthorizationSet;
 using aidl::android::hardware::security::keymint::KeyCharacteristics;
 using aidl::android::hardware::security::keymint::KeyFormat;
 
-namespace aidl::android::hardware::security::keymint {
-
-bool operator==(const keymint::AuthorizationSet& a, const keymint::AuthorizationSet& b) {
-    return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
-}
-
-}  // namespace aidl::android::hardware::security::keymint
-
 namespace std {
 
 using namespace aidl::android::hardware::security::keymint;
@@ -183,281 +170,6 @@
     void operator()(RSA* p) { RSA_free(p); }
 };
 
-char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
-                       '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
-
-string bin2hex(const vector<uint8_t>& data) {
-    string retval;
-    retval.reserve(data.size() * 2 + 1);
-    for (uint8_t byte : data) {
-        retval.push_back(nibble2hex[0x0F & (byte >> 4)]);
-        retval.push_back(nibble2hex[0x0F & byte]);
-    }
-    return retval;
-}
-
-X509* parse_cert_blob(const vector<uint8_t>& blob) {
-    const uint8_t* p = blob.data();
-    return d2i_X509(nullptr, &p, blob.size());
-}
-
-bool verify_chain(const vector<Certificate>& chain) {
-    for (size_t i = 0; i < chain.size(); ++i) {
-        X509_Ptr key_cert(parse_cert_blob(chain[i].encodedCertificate));
-        X509_Ptr signing_cert;
-        if (i < chain.size() - 1) {
-            signing_cert.reset(parse_cert_blob(chain[i + 1].encodedCertificate));
-        } else {
-            signing_cert.reset(parse_cert_blob(chain[i].encodedCertificate));
-        }
-        EXPECT_TRUE(!!key_cert.get() && !!signing_cert.get());
-        if (!key_cert.get() || !signing_cert.get()) return false;
-
-        EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
-        EXPECT_TRUE(!!signing_pubkey.get());
-        if (!signing_pubkey.get()) return false;
-
-        EXPECT_EQ(1, X509_verify(key_cert.get(), signing_pubkey.get()))
-                << "Verification of certificate " << i << " failed "
-                << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
-
-        char* cert_issuer =  //
-                X509_NAME_oneline(X509_get_issuer_name(key_cert.get()), nullptr, 0);
-        char* signer_subj =
-                X509_NAME_oneline(X509_get_subject_name(signing_cert.get()), nullptr, 0);
-        EXPECT_STREQ(cert_issuer, signer_subj) << "Cert " << i << " has wrong issuer.";
-        if (i == 0) {
-            char* cert_sub = X509_NAME_oneline(X509_get_subject_name(key_cert.get()), nullptr, 0);
-            EXPECT_STREQ("/CN=Android Keystore Key", cert_sub)
-                    << "Cert " << i << " has wrong subject.";
-            OPENSSL_free(cert_sub);
-        }
-
-        OPENSSL_free(cert_issuer);
-        OPENSSL_free(signer_subj);
-
-        if (dump_Attestations) std::cout << bin2hex(chain[i].encodedCertificate) << std::endl;
-    }
-
-    return true;
-}
-
-// Extract attestation record from cert. Returned object is still part of cert; don't free it
-// separately.
-ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
-    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
-    EXPECT_TRUE(!!oid.get());
-    if (!oid.get()) return nullptr;
-
-    int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
-    EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
-    if (location == -1) return nullptr;
-
-    X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
-    EXPECT_TRUE(!!attest_rec_ext)
-            << "Found attestation extension but couldn't retrieve it?  Probably a BoringSSL bug.";
-    if (!attest_rec_ext) return nullptr;
-
-    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
-    EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
-    return attest_rec;
-}
-
-bool tag_in_list(const KeyParameter& entry) {
-    // Attestations don't contain everything in key authorization lists, so we need to filter
-    // the key lists to produce the lists that we expect to match the attestations.
-    auto tag_list = {
-            Tag::BLOB_USAGE_REQUIREMENTS,  //
-            Tag::CREATION_DATETIME,        //
-            Tag::EC_CURVE,
-            Tag::HARDWARE_TYPE,
-            Tag::INCLUDE_UNIQUE_ID,
-    };
-    return std::find(tag_list.begin(), tag_list.end(), entry.tag) != tag_list.end();
-}
-
-AuthorizationSet filtered_tags(const AuthorizationSet& set) {
-    AuthorizationSet filtered;
-    std::remove_copy_if(set.begin(), set.end(), std::back_inserter(filtered), tag_in_list);
-    return filtered;
-}
-
-bool avb_verification_enabled() {
-    char value[PROPERTY_VALUE_MAX];
-    return property_get("ro.boot.vbmeta.device_state", value, "") != 0;
-}
-
-bool verify_attestation_record(const string& challenge,                //
-                               const string& app_id,                   //
-                               AuthorizationSet expected_sw_enforced,  //
-                               AuthorizationSet expected_hw_enforced,  //
-                               SecurityLevel security_level,
-                               const vector<uint8_t>& attestation_cert) {
-    X509_Ptr cert(parse_cert_blob(attestation_cert));
-    EXPECT_TRUE(!!cert.get());
-    if (!cert.get()) return false;
-
-    ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
-    EXPECT_TRUE(!!attest_rec);
-    if (!attest_rec) return false;
-
-    AuthorizationSet att_sw_enforced;
-    AuthorizationSet att_hw_enforced;
-    uint32_t att_attestation_version;
-    uint32_t att_keymaster_version;
-    SecurityLevel att_attestation_security_level;
-    SecurityLevel att_keymaster_security_level;
-    vector<uint8_t> att_challenge;
-    vector<uint8_t> att_unique_id;
-    vector<uint8_t> att_app_id;
-
-    auto error = parse_attestation_record(attest_rec->data,                 //
-                                          attest_rec->length,               //
-                                          &att_attestation_version,         //
-                                          &att_attestation_security_level,  //
-                                          &att_keymaster_version,           //
-                                          &att_keymaster_security_level,    //
-                                          &att_challenge,                   //
-                                          &att_sw_enforced,                 //
-                                          &att_hw_enforced,                 //
-                                          &att_unique_id);
-    EXPECT_EQ(ErrorCode::OK, error);
-    if (error != ErrorCode::OK) return false;
-
-    EXPECT_GE(att_attestation_version, 3U);
-
-    expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID,
-                                   vector<uint8_t>(app_id.begin(), app_id.end()));
-
-    EXPECT_GE(att_keymaster_version, 4U);
-    EXPECT_EQ(security_level, att_keymaster_security_level);
-    EXPECT_EQ(security_level, att_attestation_security_level);
-
-    EXPECT_EQ(challenge.length(), att_challenge.size());
-    EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
-
-    char property_value[PROPERTY_VALUE_MAX] = {};
-    // TODO(b/136282179): When running under VTS-on-GSI the TEE-backed
-    // keymaster implementation will report YYYYMM dates instead of YYYYMMDD
-    // for the BOOT_PATCH_LEVEL.
-    if (avb_verification_enabled()) {
-        for (int i = 0; i < att_hw_enforced.size(); i++) {
-            if (att_hw_enforced[i].tag == TAG_BOOT_PATCHLEVEL ||
-                att_hw_enforced[i].tag == TAG_VENDOR_PATCHLEVEL) {
-                std::string date =
-                        std::to_string(att_hw_enforced[i].value.get<KeyParameterValue::dateTime>());
-                // strptime seems to require delimiters, but the tag value will
-                // be YYYYMMDD
-                date.insert(6, "-");
-                date.insert(4, "-");
-                EXPECT_EQ(date.size(), 10);
-                struct tm time;
-                strptime(date.c_str(), "%Y-%m-%d", &time);
-
-                // Day of the month (0-31)
-                EXPECT_GE(time.tm_mday, 0);
-                EXPECT_LT(time.tm_mday, 32);
-                // Months since Jan (0-11)
-                EXPECT_GE(time.tm_mon, 0);
-                EXPECT_LT(time.tm_mon, 12);
-                // Years since 1900
-                EXPECT_GT(time.tm_year, 110);
-                EXPECT_LT(time.tm_year, 200);
-            }
-        }
-    }
-
-    // Check to make sure boolean values are properly encoded. Presence of a boolean tag indicates
-    // true. A provided boolean tag that can be pulled back out of the certificate indicates correct
-    // encoding. No need to check if it's in both lists, since the AuthorizationSet compare below
-    // will handle mismatches of tags.
-    if (security_level == SecurityLevel::SOFTWARE) {
-        EXPECT_TRUE(expected_sw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
-    } else {
-        EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
-    }
-
-    // Alternatively this checks the opposite - a false boolean tag (one that isn't provided in
-    // the authorization list during key generation) isn't being attested to in the certificate.
-    EXPECT_FALSE(expected_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
-    EXPECT_FALSE(att_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
-    EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
-    EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
-
-    if (att_hw_enforced.Contains(TAG_ALGORITHM, Algorithm::EC)) {
-        // For ECDSA keys, either an EC_CURVE or a KEY_SIZE can be specified, but one must be.
-        EXPECT_TRUE(att_hw_enforced.Contains(TAG_EC_CURVE) ||
-                    att_hw_enforced.Contains(TAG_KEY_SIZE));
-    }
-
-    // Test root of trust elements
-    vector<uint8_t> verified_boot_key;
-    VerifiedBoot verified_boot_state;
-    bool device_locked;
-    vector<uint8_t> verified_boot_hash;
-    error = parse_root_of_trust(attest_rec->data, attest_rec->length, &verified_boot_key,
-                                &verified_boot_state, &device_locked, &verified_boot_hash);
-    EXPECT_EQ(ErrorCode::OK, error);
-
-    if (avb_verification_enabled()) {
-        EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
-        string prop_string(property_value);
-        EXPECT_EQ(prop_string.size(), 64);
-        EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
-
-        EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
-        if (!strcmp(property_value, "unlocked")) {
-            EXPECT_FALSE(device_locked);
-        } else {
-            EXPECT_TRUE(device_locked);
-        }
-
-        // Check that the device is locked if not debuggable, e.g., user build
-        // images in CTS. For VTS, debuggable images are used to allow adb root
-        // and the device is unlocked.
-        if (!property_get_bool("ro.debuggable", false)) {
-            EXPECT_TRUE(device_locked);
-        } else {
-            EXPECT_FALSE(device_locked);
-        }
-    }
-
-    // Verified boot key should be all 0's if the boot state is not verified or self signed
-    std::string empty_boot_key(32, '\0');
-    std::string verified_boot_key_str((const char*)verified_boot_key.data(),
-                                      verified_boot_key.size());
-    EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
-    if (!strcmp(property_value, "green")) {
-        EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
-        EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
-                            verified_boot_key.size()));
-    } else if (!strcmp(property_value, "yellow")) {
-        EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED);
-        EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
-                            verified_boot_key.size()));
-    } else if (!strcmp(property_value, "orange")) {
-        EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
-        EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
-                            verified_boot_key.size()));
-    } else if (!strcmp(property_value, "red")) {
-        EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED);
-    } else {
-        EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
-        EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
-                            verified_boot_key.size()));
-    }
-
-    att_sw_enforced.Sort();
-    expected_sw_enforced.Sort();
-    EXPECT_EQ(filtered_tags(expected_sw_enforced), filtered_tags(att_sw_enforced));
-
-    att_hw_enforced.Sort();
-    expected_hw_enforced.Sort();
-    EXPECT_EQ(filtered_tags(expected_hw_enforced), filtered_tags(att_hw_enforced));
-
-    return true;
-}
-
 std::string make_string(const uint8_t* data, size_t length) {
     return std::string(reinterpret_cast<const char*>(data), length);
 }
@@ -596,7 +308,7 @@
                 << "Key size " << key_size << "missing";
         EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
 
-        EXPECT_TRUE(verify_chain(cert_chain_));
+        EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
         ASSERT_GT(cert_chain_.size(), 0);
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
@@ -692,7 +404,7 @@
                 << "key usage count limit " << 1U << " missing";
 
         // Check the usage count limit tag also appears in the attestation.
-        EXPECT_TRUE(verify_chain(cert_chain_));
+        EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
         ASSERT_GT(cert_chain_.size(), 0);
 
         AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
@@ -5111,14 +4823,26 @@
 }  // namespace aidl::android::hardware::security::keymint::test
 
 int main(int argc, char** argv) {
+    std::cout << "Testing ";
+    auto halInstances =
+            aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::build_params();
+    std::cout << "HAL instances:\n";
+    for (auto& entry : halInstances) {
+        std::cout << "    " << entry << '\n';
+    }
+
     ::testing::InitGoogleTest(&argc, argv);
     for (int i = 1; i < argc; ++i) {
         if (argv[i][0] == '-') {
             if (std::string(argv[i]) == "--arm_deleteAllKeys") {
-                arm_deleteAllKeys = true;
+                aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::
+                        arm_deleteAllKeys = true;
             }
             if (std::string(argv[i]) == "--dump_attestations") {
-                dump_Attestations = true;
+                aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::
+                        dump_Attestations = true;
+            } else {
+                std::cout << "NOT dumping attestations" << std::endl;
             }
         }
     }
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
new file mode 100644
index 0000000..45f9df6
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -0,0 +1,432 @@
+/*
+ * 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 "VtsRemotelyProvisionableComponentTests"
+
+#include <RemotelyProvisionedComponent.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
+#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
+#include <android/binder_manager.h>
+#include <cppbor_parse.h>
+#include <cppcose/cppcose.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <keymaster/keymaster_configuration.h>
+#include <remote_prov/remote_prov_utils.h>
+
+namespace aidl::android::hardware::security::keymint::test {
+
+using ::std::string;
+using ::std::vector;
+
+namespace {
+
+#define INSTANTIATE_REM_PROV_AIDL_TEST(name)                                         \
+    INSTANTIATE_TEST_SUITE_P(                                                        \
+            PerInstance, name,                                                       \
+            testing::ValuesIn(VtsRemotelyProvisionedComponentTests::build_params()), \
+            ::android::PrintInstanceNameToString)
+
+using bytevec = std::vector<uint8_t>;
+using testing::MatchesRegex;
+using namespace remote_prov;
+using namespace keymaster;
+
+bytevec string_to_bytevec(const char* s) {
+    const uint8_t* p = reinterpret_cast<const uint8_t*>(s);
+    return bytevec(p, p + strlen(s));
+}
+
+}  // namespace
+
+class VtsRemotelyProvisionedComponentTests : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        if (AServiceManager_isDeclared(GetParam().c_str())) {
+            ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
+            provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
+        }
+        ASSERT_NE(provisionable_, nullptr);
+    }
+
+    static vector<string> build_params() {
+        auto params = ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor);
+        return params;
+    }
+
+  protected:
+    std::shared_ptr<IRemotelyProvisionedComponent> provisionable_;
+};
+
+using GenerateKeyTests = VtsRemotelyProvisionedComponentTests;
+
+INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests);
+
+/**
+ * Generate and validate a production-mode key.  MAC tag can't be verified.
+ */
+TEST_P(GenerateKeyTests, DISABLED_generateEcdsaP256Key_prodMode) {
+    MacedPublicKey macedPubKey;
+    bytevec privateKeyBlob;
+    bool testMode = false;
+    auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
+    ASSERT_TRUE(status.isOk());
+
+    auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
+    ASSERT_TRUE(coseMac0) << "COSE Mac0 parse failed " << mac0ParseErr;
+
+    ASSERT_NE(coseMac0->asArray(), nullptr);
+    ASSERT_EQ(coseMac0->asArray()->size(), kCoseMac0EntryCount);
+
+    auto protParms = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
+    ASSERT_NE(protParms, nullptr);
+    ASSERT_EQ(cppbor::prettyPrint(protParms->value()), "{\n  1 : 5,\n}");
+
+    auto unprotParms = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asBstr();
+    ASSERT_NE(unprotParms, nullptr);
+    ASSERT_EQ(unprotParms->value().size(), 0);
+
+    auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
+    ASSERT_NE(payload, nullptr);
+    auto [parsedPayload, __, payloadParseErr] = cppbor::parse(payload->value());
+    ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
+    EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
+                MatchesRegex("{\n"
+                             "  1 : 2,\n"
+                             "  3 : -7,\n"
+                             "  -1 : 1,\n"
+                             // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a sequence of
+                             // 32 hexadecimal bytes, enclosed in braces and separated by commas.
+                             // In this case, some Ed25519 public key.
+                             "  -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"
+                             "  -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"
+                             "}"));
+
+    auto coseMac0Tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
+    ASSERT_TRUE(coseMac0Tag);
+    auto extractedTag = coseMac0Tag->value();
+    EXPECT_EQ(extractedTag.size(), 32U);
+
+    // Compare with tag generated with kTestMacKey.  Shouldn't match.
+    auto testTag = cppcose::generateCoseMac0Mac(remote_prov::kTestMacKey, {} /* external_aad */,
+                                                payload->value());
+    ASSERT_TRUE(testTag) << "Tag calculation failed: " << testTag.message();
+
+    EXPECT_NE(*testTag, extractedTag);
+}
+
+/**
+ * Generate and validate a test-mode key.
+ */
+TEST_P(GenerateKeyTests, DISABLED_generateEcdsaP256Key_testMode) {
+    MacedPublicKey macedPubKey;
+    bytevec privateKeyBlob;
+    bool testMode = true;
+    auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
+    ASSERT_TRUE(status.isOk());
+
+    auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
+    ASSERT_TRUE(coseMac0) << "COSE Mac0 parse failed " << mac0ParseErr;
+
+    ASSERT_NE(coseMac0->asArray(), nullptr);
+    ASSERT_EQ(coseMac0->asArray()->size(), kCoseMac0EntryCount);
+
+    auto protParms = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
+    ASSERT_NE(protParms, nullptr);
+    ASSERT_EQ(cppbor::prettyPrint(protParms->value()), "{\n  1 : 5,\n}");
+
+    auto unprotParms = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asBstr();
+    ASSERT_NE(unprotParms, nullptr);
+    ASSERT_EQ(unprotParms->value().size(), 0);
+
+    auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
+    ASSERT_NE(payload, nullptr);
+    auto [parsedPayload, __, payloadParseErr] = cppbor::parse(payload->value());
+    ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
+    EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
+                MatchesRegex("{\n"
+                             "  1 : 2,\n"
+                             "  3 : -7,\n"
+                             "  -1 : 1,\n"
+                             // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a sequence of
+                             // 32 hexadecimal bytes, enclosed in braces and separated by commas.
+                             // In this case, some Ed25519 public key.
+                             "  -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"
+                             "  -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"
+                             "  -70000 : null,\n"
+                             "}"));
+
+    auto coseMac0Tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
+    ASSERT_TRUE(coseMac0);
+    auto extractedTag = coseMac0Tag->value();
+    EXPECT_EQ(extractedTag.size(), 32U);
+
+    // Compare with tag generated with kTestMacKey.  Should match.
+    auto testTag = cppcose::generateCoseMac0Mac(remote_prov::kTestMacKey, {} /* external_aad */,
+                                                payload->value());
+    ASSERT_TRUE(testTag) << testTag.message();
+
+    EXPECT_EQ(*testTag, extractedTag);
+}
+
+class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
+  protected:
+    CertificateRequestTest() : eekId_(string_to_bytevec("eekid")) {
+        auto chain = generateEekChain(3, eekId_);
+        EXPECT_TRUE(chain) << chain.message();
+        if (chain) eekChain_ = chain.moveValue();
+    }
+
+    void generateKeys(bool testMode, size_t numKeys) {
+        keysToSign_ = std::vector<MacedPublicKey>(numKeys);
+        cborKeysToSign_ = cppbor::Array();
+
+        for (auto& key : keysToSign_) {
+            bytevec privateKeyBlob;
+            auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &key, &privateKeyBlob);
+            ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+            auto [parsedMacedKey, _, parseErr] = cppbor::parse(key.macedKey);
+            ASSERT_TRUE(parsedMacedKey) << "Failed parsing MACed key: " << parseErr;
+            ASSERT_TRUE(parsedMacedKey->asArray()) << "COSE_Mac0 not an array?";
+            ASSERT_EQ(parsedMacedKey->asArray()->size(), kCoseMac0EntryCount);
+
+            auto& payload = parsedMacedKey->asArray()->get(kCoseMac0Payload);
+            ASSERT_TRUE(payload);
+            ASSERT_TRUE(payload->asBstr());
+
+            cborKeysToSign_.add(cppbor::EncodedItem(payload->asBstr()->value()));
+        }
+    }
+
+    bytevec eekId_;
+    EekChain eekChain_;
+    std::vector<MacedPublicKey> keysToSign_;
+    cppbor::Array cborKeysToSign_;
+};
+
+/**
+ * Generate an empty certificate request in test mode, and decrypt and verify the structure and
+ * content.
+ */
+TEST_P(CertificateRequestTest, DISABLED_EmptyRequest_testMode) {
+    bool testMode = true;
+    bytevec keysToSignMac;
+    ProtectedData protectedData;
+    auto challenge = randomBytes(32);
+    auto status = provisionable_->generateCertificateRequest(testMode, {} /* keysToSign */,
+                                                             eekChain_.chain, challenge,
+                                                             &keysToSignMac, &protectedData);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+    auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
+    ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
+    ASSERT_TRUE(parsedProtectedData->asArray());
+    ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
+
+    auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
+    ASSERT_TRUE(senderPubkey) << senderPubkey.message();
+    EXPECT_EQ(senderPubkey->second, eekId_);
+
+    auto sessionKey = x25519_HKDF_DeriveKey(eekChain_.last_pubkey, eekChain_.last_privkey,
+                                            senderPubkey->first, false /* senderIsA */);
+    ASSERT_TRUE(sessionKey) << sessionKey.message();
+
+    auto protectedDataPayload =
+            decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
+    ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
+
+    auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
+    ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
+    ASSERT_TRUE(parsedPayload->asArray());
+    EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
+
+    auto& signedMac = parsedPayload->asArray()->get(0);
+    auto& bcc = parsedPayload->asArray()->get(1);
+    ASSERT_TRUE(signedMac && signedMac->asArray());
+    ASSERT_TRUE(bcc && bcc->asArray());
+
+    // BCC is [ pubkey, + BccEntry]
+    auto bccContents = validateBcc(bcc->asArray());
+    ASSERT_TRUE(bccContents) << "\n" << bccContents.message() << "\n" << prettyPrint(bcc.get());
+    ASSERT_GT(bccContents->size(), 0U);
+
+    auto& signingKey = bccContents->back().pubKey;
+    auto macKey = verifyAndParseCoseSign1(testMode, signedMac->asArray(), signingKey,
+                                          cppbor::Array()          // DeviceInfo
+                                                  .add(challenge)  //
+                                                  .add(cppbor::Map())
+                                                  .encode());
+    ASSERT_TRUE(macKey) << macKey.message();
+
+    auto coseMac0 = cppbor::Array()
+                            .add(cppbor::Map()  // protected
+                                         .add(ALGORITHM, HMAC_256)
+                                         .canonicalize()
+                                         .encode())
+                            .add(cppbor::Bstr())             // unprotected
+                            .add(cppbor::Array().encode())   // payload (keysToSign)
+                            .add(std::move(keysToSignMac));  // tag
+
+    auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
+    ASSERT_TRUE(macPayload) << macPayload.message();
+}
+
+/**
+ * Generate an empty certificate request in prod mode.  Generation will fail because we don't have a
+ * valid GEEK.
+ *
+ * TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
+ * able to decrypt.
+ */
+TEST_P(CertificateRequestTest, DISABLED_EmptyRequest_prodMode) {
+    bool testMode = false;
+    bytevec keysToSignMac;
+    ProtectedData protectedData;
+    auto challenge = randomBytes(32);
+    auto status = provisionable_->generateCertificateRequest(testMode, {} /* keysToSign */,
+                                                             eekChain_.chain, challenge,
+                                                             &keysToSignMac, &protectedData);
+    ASSERT_FALSE(status.isOk());
+    ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
+}
+
+/**
+ * Generate a non-empty certificate request in test mode.  Decrypt, parse and validate the contents.
+ */
+TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_testMode) {
+    bool testMode = true;
+    generateKeys(testMode, 4 /* numKeys */);
+
+    bytevec keysToSignMac;
+    ProtectedData protectedData;
+    auto challenge = randomBytes(32);
+    auto status = provisionable_->generateCertificateRequest(
+            testMode, keysToSign_, eekChain_.chain, challenge, &keysToSignMac, &protectedData);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+    auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
+    ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
+    ASSERT_TRUE(parsedProtectedData->asArray());
+    ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
+
+    auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
+    ASSERT_TRUE(senderPubkey) << senderPubkey.message();
+    EXPECT_EQ(senderPubkey->second, eekId_);
+
+    auto sessionKey = x25519_HKDF_DeriveKey(eekChain_.last_pubkey, eekChain_.last_privkey,
+                                            senderPubkey->first, false /* senderIsA */);
+    ASSERT_TRUE(sessionKey) << sessionKey.message();
+
+    auto protectedDataPayload =
+            decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
+    ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
+
+    auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
+    ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
+    ASSERT_TRUE(parsedPayload->asArray());
+    EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
+
+    auto& signedMac = parsedPayload->asArray()->get(0);
+    auto& bcc = parsedPayload->asArray()->get(1);
+    ASSERT_TRUE(signedMac && signedMac->asArray());
+    ASSERT_TRUE(bcc);
+
+    auto bccContents = validateBcc(bcc->asArray());
+    ASSERT_TRUE(bccContents) << "\n" << prettyPrint(bcc.get());
+    ASSERT_GT(bccContents->size(), 0U);
+
+    auto& signingKey = bccContents->back().pubKey;
+    auto macKey = verifyAndParseCoseSign1(testMode, signedMac->asArray(), signingKey,
+                                          cppbor::Array()          // DeviceInfo
+                                                  .add(challenge)  //
+                                                  .add(cppbor::Array())
+                                                  .encode());
+    ASSERT_TRUE(macKey) << macKey.message();
+
+    auto coseMac0 = cppbor::Array()
+                            .add(cppbor::Map()  // protected
+                                         .add(ALGORITHM, HMAC_256)
+                                         .canonicalize()
+                                         .encode())
+                            .add(cppbor::Bstr())             // unprotected
+                            .add(cborKeysToSign_.encode())   // payload
+                            .add(std::move(keysToSignMac));  // tag
+
+    auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
+    ASSERT_TRUE(macPayload) << macPayload.message();
+}
+
+/**
+ * Generate a non-empty certificate request in prod mode.  Must fail because we don't have a valid
+ * GEEK.
+ *
+ * TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
+ * able to decrypt.
+ */
+TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_prodMode) {
+    bool testMode = false;
+    generateKeys(testMode, 4 /* numKeys */);
+
+    bytevec keysToSignMac;
+    ProtectedData protectedData;
+    auto challenge = randomBytes(32);
+    auto status = provisionable_->generateCertificateRequest(
+            testMode, keysToSign_, eekChain_.chain, challenge, &keysToSignMac, &protectedData);
+    ASSERT_FALSE(status.isOk());
+    ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
+}
+
+/**
+ * Generate a non-empty certificate request in test mode, with prod keys.  Must fail with
+ * STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
+ */
+TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_prodKeyInTestCert) {
+    generateKeys(false /* testMode */, 2 /* numKeys */);
+
+    bytevec keysToSignMac;
+    ProtectedData protectedData;
+    auto challenge = randomBytes(32);
+    auto status = provisionable_->generateCertificateRequest(true /* testMode */, keysToSign_,
+                                                             eekChain_.chain, challenge,
+                                                             &keysToSignMac, &protectedData);
+    ASSERT_FALSE(status.isOk());
+    ASSERT_EQ(status.getServiceSpecificError(),
+              BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST);
+}
+
+/**
+ * Generate a non-empty certificate request in prod mode, with test keys.  Must fail with
+ * STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
+ */
+TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_testKeyInProdCert) {
+    generateKeys(true /* testMode */, 2 /* numKeys */);
+
+    bytevec keysToSignMac;
+    ProtectedData protectedData;
+    auto status = provisionable_->generateCertificateRequest(
+            false /* testMode */, keysToSign_, eekChain_.chain, randomBytes(32) /* challenge */,
+            &keysToSignMac, &protectedData);
+    ASSERT_FALSE(status.isOk());
+    ASSERT_EQ(status.getServiceSpecificError(),
+              BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
+}
+
+INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestTest);
+
+}  // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
index fde6b57..0255874 100644
--- a/security/keymint/support/Android.bp
+++ b/security/keymint/support/Android.bp
@@ -37,3 +37,40 @@
         "libutils",
     ],
 }
+
+cc_library {
+    name: "libkeymint_remote_prov_support",
+    vendor_available: true,
+    srcs: [
+        "remote_prov_utils.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+    shared_libs: [
+        "libcppcose",
+        "libcppbor_external",
+        "libcrypto",
+    ],
+}
+
+cc_library {
+    name: "libcppcose",
+    vendor_available: true,
+    srcs: [
+        "cppcose.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcppbor_external",
+        "libcrypto",
+        "liblog",
+    ],
+    static_libs: [
+        // TODO(swillden): Remove keymint NDK
+        "android.hardware.security.keymint-V1-ndk_platform",
+    ],
+}
diff --git a/security/keymint/support/authorization_set.cpp b/security/keymint/support/authorization_set.cpp
index 8d42571..25eace3 100644
--- a/security/keymint/support/authorization_set.cpp
+++ b/security/keymint/support/authorization_set.cpp
@@ -191,6 +191,10 @@
     return Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT);
 }
 
+AuthorizationSetBuilder& AuthorizationSetBuilder::AttestKey() {
+    return Authorization(TAG_PURPOSE, KeyPurpose::ATTEST_KEY);
+}
+
 AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() {
     Authorization(TAG_DIGEST, Digest::NONE);
     return Authorization(TAG_PADDING, PaddingMode::NONE);
diff --git a/security/keymint/support/cppcose.cpp b/security/keymint/support/cppcose.cpp
new file mode 100644
index 0000000..c626ade
--- /dev/null
+++ b/security/keymint/support/cppcose.cpp
@@ -0,0 +1,467 @@
+/*
+ * 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.
+ */
+
+#include <cppcose/cppcose.h>
+
+#include <stdio.h>
+#include <iostream>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+#include <openssl/err.h>
+
+namespace cppcose {
+
+namespace {
+
+ErrMsgOr<bssl::UniquePtr<EVP_CIPHER_CTX>> aesGcmInitAndProcessAad(const bytevec& key,
+                                                                  const bytevec& nonce,
+                                                                  const bytevec& aad,
+                                                                  bool encrypt) {
+    if (key.size() != kAesGcmKeySize) return "Invalid key size";
+
+    bssl::UniquePtr<EVP_CIPHER_CTX> ctx(EVP_CIPHER_CTX_new());
+    if (!ctx) return "Failed to allocate cipher context";
+
+    if (!EVP_CipherInit_ex(ctx.get(), EVP_aes_256_gcm(), nullptr /* engine */, key.data(),
+                           nonce.data(), encrypt ? 1 : 0)) {
+        return "Failed to initialize cipher";
+    }
+
+    int outlen;
+    if (!aad.empty() && !EVP_CipherUpdate(ctx.get(), nullptr /* out; null means AAD */, &outlen,
+                                          aad.data(), aad.size())) {
+        return "Failed to process AAD";
+    }
+
+    return std::move(ctx);
+}
+
+}  // namespace
+
+ErrMsgOr<bytevec> generateCoseMac0Mac(const bytevec& macKey, const bytevec& externalAad,
+                                      const bytevec& payload) {
+    auto macStructure = cppbor::Array()
+                                .add("MAC0")
+                                .add(cppbor::Map().add(ALGORITHM, HMAC_256).canonicalize().encode())
+                                .add(externalAad)
+                                .add(payload)
+                                .encode();
+
+    bytevec macTag(SHA256_DIGEST_LENGTH);
+    uint8_t* out = macTag.data();
+    unsigned int outLen;
+    out = HMAC(EVP_sha256(),                              //
+               macKey.data(), macKey.size(),              //
+               macStructure.data(), macStructure.size(),  //
+               out, &outLen);
+
+    assert(out != nullptr && outLen == macTag.size());
+    if (out == nullptr || outLen != macTag.size()) {
+        return "Error computing public key MAC";
+    }
+
+    return macTag;
+}
+
+ErrMsgOr<cppbor::Array> constructCoseMac0(const bytevec& macKey, const bytevec& externalAad,
+                                          const bytevec& payload) {
+    auto tag = generateCoseMac0Mac(macKey, externalAad, payload);
+    if (!tag) return tag.moveMessage();
+
+    return cppbor::Array()
+            .add(cppbor::Map().add(ALGORITHM, HMAC_256).canonicalize().encode())
+            .add(cppbor::Bstr() /* unprotected */)
+            .add(payload)
+            .add(tag.moveValue());
+}
+
+ErrMsgOr<bytevec /* payload */> parseCoseMac0(const cppbor::Item* macItem) {
+    auto mac = macItem ? macItem->asArray() : nullptr;
+    if (!mac || mac->size() != kCoseMac0EntryCount) {
+        return "Invalid COSE_Mac0";
+    }
+
+    auto protectedParms = mac->get(kCoseMac0ProtectedParams)->asBstr();
+    auto unprotectedParms = mac->get(kCoseMac0UnprotectedParams)->asBstr();
+    auto payload = mac->get(kCoseMac0Payload)->asBstr();
+    auto tag = mac->get(kCoseMac0Tag)->asBstr();
+    if (!protectedParms || !unprotectedParms || !payload || !tag) {
+        return "Invalid COSE_Mac0 contents";
+    }
+
+    return payload->value();
+}
+
+ErrMsgOr<bytevec /* payload */> verifyAndParseCoseMac0(const cppbor::Item* macItem,
+                                                       const bytevec& macKey) {
+    auto mac = macItem ? macItem->asArray() : nullptr;
+    if (!mac || mac->size() != kCoseMac0EntryCount) {
+        return "Invalid COSE_Mac0";
+    }
+
+    auto protectedParms = mac->get(kCoseMac0ProtectedParams)->asBstr();
+    auto unprotectedParms = mac->get(kCoseMac0UnprotectedParams)->asBstr();
+    auto payload = mac->get(kCoseMac0Payload)->asBstr();
+    auto tag = mac->get(kCoseMac0Tag)->asBstr();
+    if (!protectedParms || !unprotectedParms || !payload || !tag) {
+        return "Invalid COSE_Mac0 contents";
+    }
+
+    auto [protectedMap, _, errMsg] = cppbor::parse(protectedParms);
+    if (!protectedMap || !protectedMap->asMap()) {
+        return "Invalid Mac0 protected: " + errMsg;
+    }
+    auto& algo = protectedMap->asMap()->get(ALGORITHM);
+    if (!algo || !algo->asInt() || algo->asInt()->value() != HMAC_256) {
+        return "Unsupported Mac0 algorithm";
+    }
+
+    auto macTag = generateCoseMac0Mac(macKey, {} /* external_aad */, payload->value());
+    if (!macTag) return macTag.moveMessage();
+
+    if (macTag->size() != tag->value().size() ||
+        CRYPTO_memcmp(macTag->data(), tag->value().data(), macTag->size()) != 0) {
+        return "MAC tag mismatch";
+    }
+
+    return payload->value();
+}
+
+ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
+                                           const bytevec& payload, const bytevec& aad) {
+    bytevec signatureInput = cppbor::Array()
+                                     .add("Signature1")  //
+                                     .add(protectedParams)
+                                     .add(aad)
+                                     .add(payload)
+                                     .encode();
+
+    if (key.size() != ED25519_PRIVATE_KEY_LEN) return "Invalid signing key";
+    bytevec signature(ED25519_SIGNATURE_LEN);
+    if (!ED25519_sign(signature.data(), signatureInput.data(), signatureInput.size(), key.data())) {
+        return "Signing failed";
+    }
+
+    return signature;
+}
+
+ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, cppbor::Map protectedParams,
+                                           const bytevec& payload, const bytevec& aad) {
+    bytevec protParms = protectedParams.add(ALGORITHM, EDDSA).canonicalize().encode();
+    auto signature = createCoseSign1Signature(key, protParms, payload, aad);
+    if (!signature) return signature.moveMessage();
+
+    return cppbor::Array()
+            .add(protParms)
+            .add(bytevec{} /* unprotected parameters */)
+            .add(payload)
+            .add(*signature);
+}
+
+ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, const bytevec& payload,
+                                           const bytevec& aad) {
+    return constructCoseSign1(key, {} /* protectedParams */, payload, aad);
+}
+
+ErrMsgOr<bytevec> verifyAndParseCoseSign1(bool ignoreSignature, const cppbor::Array* coseSign1,
+                                          const bytevec& signingCoseKey, const bytevec& aad) {
+    if (!coseSign1 || coseSign1->size() != kCoseSign1EntryCount) {
+        return "Invalid COSE_Sign1";
+    }
+
+    const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
+    const cppbor::Bstr* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asBstr();
+    const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
+    const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
+
+    if (!protectedParams || !unprotectedParams || !payload || !signature) {
+        return "Invalid COSE_Sign1";
+    }
+
+    auto [parsedProtParams, _, errMsg] = cppbor::parse(protectedParams);
+    if (!parsedProtParams) {
+        return errMsg + " when parsing protected params.";
+    }
+    if (!parsedProtParams->asMap()) {
+        return "Protected params must be a map";
+    }
+
+    auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
+    if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != EDDSA) {
+        return "Unsupported signature algorithm";
+    }
+
+    if (!ignoreSignature) {
+        bool selfSigned = signingCoseKey.empty();
+        auto key = CoseKey::parseEd25519(selfSigned ? payload->value() : signingCoseKey);
+        if (!key) return "Bad signing key: " + key.moveMessage();
+
+        bytevec signatureInput = 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";
+        }
+    }
+
+    return payload->value();
+}
+
+ErrMsgOr<bytevec> createCoseEncryptCiphertext(const bytevec& key, const bytevec& nonce,
+                                              const bytevec& protectedParams,
+                                              const bytevec& plaintextPayload, const bytevec& aad) {
+    auto ciphertext = aesGcmEncrypt(key, nonce,
+                                    cppbor::Array()                // Enc strucure as AAD
+                                            .add("Encrypt")        // Context
+                                            .add(protectedParams)  // Protected
+                                            .add(aad)              // External AAD
+                                            .encode(),
+                                    plaintextPayload);
+
+    if (!ciphertext) return ciphertext.moveMessage();
+    return ciphertext.moveValue();
+}
+
+ErrMsgOr<cppbor::Array> constructCoseEncrypt(const bytevec& key, const bytevec& nonce,
+                                             const bytevec& plaintextPayload, const bytevec& aad,
+                                             cppbor::Array recipients) {
+    auto encryptProtectedHeader = cppbor::Map()  //
+                                          .add(ALGORITHM, AES_GCM_256)
+                                          .canonicalize()
+                                          .encode();
+
+    auto ciphertext =
+            createCoseEncryptCiphertext(key, nonce, encryptProtectedHeader, plaintextPayload, aad);
+    if (!ciphertext) return ciphertext.moveMessage();
+
+    return cppbor::Array()
+            .add(encryptProtectedHeader)                       // Protected
+            .add(cppbor::Map().add(IV, nonce).canonicalize())  // Unprotected
+            .add(*ciphertext)                                  // Payload
+            .add(std::move(recipients));
+}
+
+ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>> getSenderPubKeyFromCoseEncrypt(
+        const cppbor::Item* coseEncrypt) {
+    if (!coseEncrypt || !coseEncrypt->asArray() ||
+        coseEncrypt->asArray()->size() != kCoseEncryptEntryCount) {
+        return "Invalid COSE_Encrypt";
+    }
+
+    auto& recipients = coseEncrypt->asArray()->get(kCoseEncryptRecipients);
+    if (!recipients || !recipients->asArray() || recipients->asArray()->size() != 1) {
+        return "Invalid recipients list";
+    }
+
+    auto& recipient = recipients->asArray()->get(0);
+    if (!recipient || !recipient->asArray() || recipient->asArray()->size() != 3) {
+        return "Invalid COSE_recipient";
+    }
+
+    auto& ciphertext = recipient->asArray()->get(2);
+    if (!ciphertext->asSimple() || !ciphertext->asSimple()->asNull()) {
+        return "Unexpected value in recipients ciphertext field " +
+               cppbor::prettyPrint(ciphertext.get());
+    }
+
+    auto& protParms = recipient->asArray()->get(0);
+    if (!protParms || !protParms->asBstr()) return "Invalid protected params";
+    auto [parsedProtParms, _, errMsg] = cppbor::parse(protParms->asBstr());
+    if (!parsedProtParms) return "Failed to parse protected params: " + errMsg;
+    if (!parsedProtParms->asMap()) return "Invalid protected params";
+
+    auto& algorithm = parsedProtParms->asMap()->get(ALGORITHM);
+    if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != ECDH_ES_HKDF_256) {
+        return "Invalid algorithm";
+    }
+
+    auto& unprotParms = recipient->asArray()->get(1);
+    if (!unprotParms || !unprotParms->asMap()) return "Invalid unprotected params";
+
+    auto& senderCoseKey = unprotParms->asMap()->get(COSE_KEY);
+    if (!senderCoseKey || !senderCoseKey->asMap()) return "Invalid sender COSE_Key";
+
+    auto& keyType = senderCoseKey->asMap()->get(CoseKey::KEY_TYPE);
+    if (!keyType || !keyType->asInt() || keyType->asInt()->value() != OCTET_KEY_PAIR) {
+        return "Invalid key type";
+    }
+
+    auto& curve = senderCoseKey->asMap()->get(CoseKey::CURVE);
+    if (!curve || !curve->asInt() || curve->asInt()->value() != X25519) {
+        return "Unsupported curve";
+    }
+
+    auto& pubkey = senderCoseKey->asMap()->get(CoseKey::PUBKEY_X);
+    if (!pubkey || !pubkey->asBstr() ||
+        pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) {
+        return "Invalid X25519 public key";
+    }
+
+    auto& key_id = unprotParms->asMap()->get(KEY_ID);
+    if (key_id && key_id->asBstr()) {
+        return std::make_pair(pubkey->asBstr()->value(), key_id->asBstr()->value());
+    }
+
+    // If no key ID, just return an empty vector.
+    return std::make_pair(pubkey->asBstr()->value(), bytevec{});
+}
+
+ErrMsgOr<bytevec> decryptCoseEncrypt(const bytevec& key, const cppbor::Item* coseEncrypt,
+                                     const bytevec& external_aad) {
+    if (!coseEncrypt || !coseEncrypt->asArray() ||
+        coseEncrypt->asArray()->size() != kCoseEncryptEntryCount) {
+        return "Invalid COSE_Encrypt";
+    }
+
+    auto& protParms = coseEncrypt->asArray()->get(kCoseEncryptProtectedParams);
+    auto& unprotParms = coseEncrypt->asArray()->get(kCoseEncryptUnprotectedParams);
+    auto& ciphertext = coseEncrypt->asArray()->get(kCoseEncryptPayload);
+    auto& recipients = coseEncrypt->asArray()->get(kCoseEncryptRecipients);
+
+    if (!protParms || !protParms->asBstr() || !unprotParms || !ciphertext || !recipients) {
+        return "Invalid COSE_Encrypt";
+    }
+
+    auto [parsedProtParams, _, errMsg] = cppbor::parse(protParms->asBstr()->value());
+    if (!parsedProtParams) {
+        return errMsg + " when parsing protected params.";
+    }
+    if (!parsedProtParams->asMap()) {
+        return "Protected params must be a map";
+    }
+
+    auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
+    if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != AES_GCM_256) {
+        return "Unsupported encryption algorithm";
+    }
+
+    if (!unprotParms->asMap() || unprotParms->asMap()->size() != 1) {
+        return "Invalid unprotected params";
+    }
+
+    auto& nonce = unprotParms->asMap()->get(IV);
+    if (!nonce || !nonce->asBstr() || nonce->asBstr()->value().size() != kAesGcmNonceLength) {
+        return "Invalid nonce";
+    }
+
+    if (!ciphertext->asBstr()) return "Invalid ciphertext";
+
+    auto aad = cppbor::Array()                             // Enc strucure as AAD
+                       .add("Encrypt")                     // Context
+                       .add(protParms->asBstr()->value())  // Protected
+                       .add(external_aad)                  // External AAD
+                       .encode();
+
+    return aesGcmDecrypt(key, nonce->asBstr()->value(), aad, ciphertext->asBstr()->value());
+}
+
+ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA,
+                                        const bytevec& pubKeyB, bool senderIsA) {
+    bytevec rawSharedKey(X25519_SHARED_KEY_LEN);
+    if (!::X25519(rawSharedKey.data(), privKeyA.data(), pubKeyB.data())) {
+        return "ECDH operation failed";
+    }
+
+    bytevec kdfContext = cppbor::Array()
+                                 .add(AES_GCM_256)
+                                 .add(cppbor::Array()  // Sender Info
+                                              .add(cppbor::Bstr("client"))
+                                              .add(bytevec{} /* nonce */)
+                                              .add(senderIsA ? pubKeyA : pubKeyB))
+                                 .add(cppbor::Array()  // Recipient Info
+                                              .add(cppbor::Bstr("server"))
+                                              .add(bytevec{} /* nonce */)
+                                              .add(senderIsA ? pubKeyB : pubKeyA))
+                                 .add(cppbor::Array()           // SuppPubInfo
+                                              .add(128)         // output key length
+                                              .add(bytevec{}))  // protected
+                                 .encode();
+
+    bytevec retval(SHA256_DIGEST_LENGTH);
+    bytevec salt{};
+    if (!HKDF(retval.data(), retval.size(),              //
+              EVP_sha256(),                              //
+              rawSharedKey.data(), rawSharedKey.size(),  //
+              salt.data(), salt.size(),                  //
+              kdfContext.data(), kdfContext.size())) {
+        return "ECDH HKDF failed";
+    }
+
+    return retval;
+}
+
+ErrMsgOr<bytevec> aesGcmEncrypt(const bytevec& key, const bytevec& nonce, const bytevec& aad,
+                                const bytevec& plaintext) {
+    auto ctx = aesGcmInitAndProcessAad(key, nonce, aad, true /* encrypt */);
+    if (!ctx) return ctx.moveMessage();
+
+    bytevec ciphertext(plaintext.size() + kAesGcmTagSize);
+    int outlen;
+    if (!EVP_CipherUpdate(ctx->get(), ciphertext.data(), &outlen, plaintext.data(),
+                          plaintext.size())) {
+        return "Failed to encrypt plaintext";
+    }
+    assert(plaintext.size() == outlen);
+
+    if (!EVP_CipherFinal_ex(ctx->get(), ciphertext.data() + outlen, &outlen)) {
+        return "Failed to finalize encryption";
+    }
+    assert(outlen == 0);
+
+    if (!EVP_CIPHER_CTX_ctrl(ctx->get(), EVP_CTRL_GCM_GET_TAG, kAesGcmTagSize,
+                             ciphertext.data() + plaintext.size())) {
+        return "Failed to retrieve tag";
+    }
+
+    return ciphertext;
+}
+
+ErrMsgOr<bytevec> aesGcmDecrypt(const bytevec& key, const bytevec& nonce, const bytevec& aad,
+                                const bytevec& ciphertextWithTag) {
+    auto ctx = aesGcmInitAndProcessAad(key, nonce, aad, false /* encrypt */);
+    if (!ctx) return ctx.moveMessage();
+
+    if (ciphertextWithTag.size() < kAesGcmTagSize) return "Missing tag";
+
+    bytevec plaintext(ciphertextWithTag.size() - kAesGcmTagSize);
+    int outlen;
+    if (!EVP_CipherUpdate(ctx->get(), plaintext.data(), &outlen, ciphertextWithTag.data(),
+                          ciphertextWithTag.size() - kAesGcmTagSize)) {
+        return "Failed to decrypt plaintext";
+    }
+    assert(plaintext.size() == outlen);
+
+    bytevec tag(ciphertextWithTag.end() - kAesGcmTagSize, ciphertextWithTag.end());
+    if (!EVP_CIPHER_CTX_ctrl(ctx->get(), EVP_CTRL_GCM_SET_TAG, kAesGcmTagSize, tag.data())) {
+        return "Failed to set tag: " + std::to_string(ERR_peek_last_error());
+    }
+
+    if (!EVP_CipherFinal_ex(ctx->get(), nullptr, &outlen)) {
+        return "Failed to finalize encryption";
+    }
+    assert(outlen == 0);
+
+    return plaintext;
+}
+
+}  // namespace cppcose
diff --git a/security/keymint/support/include/cppcose/cppcose.h b/security/keymint/support/include/cppcose/cppcose.h
new file mode 100644
index 0000000..a936bfd
--- /dev/null
+++ b/security/keymint/support/include/cppcose/cppcose.h
@@ -0,0 +1,288 @@
+/*
+ * 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 <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+#include <openssl/cipher.h>
+#include <openssl/curve25519.h>
+#include <openssl/digest.h>
+#include <openssl/hkdf.h>
+#include <openssl/hmac.h>
+#include <openssl/mem.h>
+#include <openssl/sha.h>
+
+namespace cppcose {
+
+using bytevec = std::vector<uint8_t>;
+
+constexpr int kCoseSign1EntryCount = 4;
+constexpr int kCoseSign1ProtectedParams = 0;
+constexpr int kCoseSign1UnprotectedParams = 1;
+constexpr int kCoseSign1Payload = 2;
+constexpr int kCoseSign1Signature = 3;
+
+constexpr int kCoseMac0EntryCount = 4;
+constexpr int kCoseMac0ProtectedParams = 0;
+constexpr int kCoseMac0UnprotectedParams = 1;
+constexpr int kCoseMac0Payload = 2;
+constexpr int kCoseMac0Tag = 3;
+
+constexpr int kCoseEncryptEntryCount = 4;
+constexpr int kCoseEncryptProtectedParams = 0;
+constexpr int kCoseEncryptUnprotectedParams = 1;
+constexpr int kCoseEncryptPayload = 2;
+constexpr int kCoseEncryptRecipients = 3;
+
+enum Label : int {
+    ALGORITHM = 1,
+    KEY_ID = 4,
+    IV = 5,
+    COSE_KEY = -1,
+};
+
+enum CoseKeyAlgorithm : int {
+    AES_GCM_256 = 3,
+    HMAC_256 = 5,
+    ES256 = -7,  // ECDSA with SHA-256
+    EDDSA = -8,
+    ECDH_ES_HKDF_256 = -25,
+};
+
+enum CoseKeyCurve : int { P256 = 1, X25519 = 4, ED25519 = 6 };
+enum CoseKeyType : int { OCTET_KEY_PAIR = 1, EC2 = 2, SYMMETRIC_KEY = 4 };
+enum CoseKeyOps : int { SIGN = 1, VERIFY = 2, ENCRYPT = 3, DECRYPT = 4 };
+
+constexpr int kAesGcmNonceLength = 12;
+constexpr int kAesGcmTagSize = 16;
+constexpr int kAesGcmKeySize = 32;
+
+template <typename T>
+class ErrMsgOr {
+  public:
+    ErrMsgOr(std::string errMsg) : errMsg_(std::move(errMsg)) {}
+    ErrMsgOr(const char* errMsg) : errMsg_(errMsg) {}
+    ErrMsgOr(T val) : value_(std::move(val)) {}
+
+    operator bool() const { return value_.has_value(); }
+
+    T* operator->() & {
+        assert(value_);
+        return &value_.value();
+    }
+    T& operator*() & {
+        assert(value_);
+        return value_.value();
+    };
+    T&& operator*() && {
+        assert(value_);
+        return std::move(value_).value();
+    };
+
+    const std::string& message() { return errMsg_; }
+    std::string moveMessage() { return std::move(errMsg_); }
+
+    T moveValue() {
+        assert(value_);
+        return std::move(value_).value();
+    }
+
+  private:
+    std::string errMsg_;
+    std::optional<T> value_;
+};
+
+class CoseKey {
+  public:
+    CoseKey() {}
+    CoseKey(const CoseKey&) = delete;
+    CoseKey(CoseKey&&) = default;
+
+    enum Label : int {
+        KEY_TYPE = 1,
+        KEY_ID = 2,
+        ALGORITHM = 3,
+        KEY_OPS = 4,
+        CURVE = -1,
+        PUBKEY_X = -2,
+        PUBKEY_Y = -3,
+        PRIVATE_KEY = -4,
+        TEST_KEY = -70000  // Application-defined
+    };
+
+    static ErrMsgOr<CoseKey> parse(const bytevec& coseKey) {
+        auto [parsedKey, _, errMsg] = cppbor::parse(coseKey);
+        if (!parsedKey) return errMsg + " when parsing key";
+        if (!parsedKey->asMap()) return "CoseKey must be a map";
+        return CoseKey(static_cast<cppbor::Map*>(parsedKey.release()));
+    }
+
+    static ErrMsgOr<CoseKey> parse(const bytevec& coseKey, CoseKeyType expectedKeyType,
+                                   CoseKeyAlgorithm expectedAlgorithm, CoseKeyCurve expectedCurve) {
+        auto key = parse(coseKey);
+        if (!key) return key;
+
+        if (!key->checkIntValue(CoseKey::KEY_TYPE, expectedKeyType) ||
+            !key->checkIntValue(CoseKey::ALGORITHM, expectedAlgorithm) ||
+            !key->checkIntValue(CoseKey::CURVE, expectedCurve)) {
+            return "Unexpected key type:";
+        }
+
+        return key;
+    }
+
+    static ErrMsgOr<CoseKey> parseEd25519(const bytevec& coseKey) {
+        auto key = parse(coseKey, OCTET_KEY_PAIR, EDDSA, ED25519);
+        if (!key) return key;
+
+        auto& pubkey = key->getMap().get(PUBKEY_X);
+        if (!pubkey || !pubkey->asBstr() ||
+            pubkey->asBstr()->value().size() != ED25519_PUBLIC_KEY_LEN) {
+            return "Invalid Ed25519 public key";
+        }
+
+        return key;
+    }
+
+    static ErrMsgOr<CoseKey> parseX25519(const bytevec& coseKey, bool requireKid) {
+        auto key = parse(coseKey, OCTET_KEY_PAIR, ECDH_ES_HKDF_256, X25519);
+        if (!key) return key;
+
+        auto& pubkey = key->getMap().get(PUBKEY_X);
+        if (!pubkey || !pubkey->asBstr() ||
+            pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) {
+            return "Invalid X25519 public key";
+        }
+
+        auto& kid = key->getMap().get(KEY_ID);
+        if (requireKid && (!kid || !kid->asBstr())) {
+            return "Missing KID";
+        }
+
+        return key;
+    }
+
+    static ErrMsgOr<CoseKey> parseP256(const bytevec& coseKey) {
+        auto key = parse(coseKey, EC2, ES256, P256);
+        if (!key) return key;
+
+        auto& pubkey_x = key->getMap().get(PUBKEY_X);
+        auto& pubkey_y = key->getMap().get(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;
+    }
+
+    std::optional<int> getIntValue(Label label) {
+        const auto& value = key_->get(label);
+        if (!value || !value->asInt()) return {};
+        return value->asInt()->value();
+    }
+
+    std::optional<bytevec> getBstrValue(Label label) {
+        const auto& value = key_->get(label);
+        if (!value || !value->asBstr()) return {};
+        return value->asBstr()->value();
+    }
+
+    const cppbor::Map& getMap() const { return *key_; }
+    cppbor::Map&& moveMap() { return std::move(*key_); }
+
+    bool checkIntValue(Label label, int expectedValue) {
+        const auto& value = key_->get(label);
+        return value && value->asInt() && value->asInt()->value() == expectedValue;
+    }
+
+    void add(Label label, int value) { key_->add(label, value); }
+    void add(Label label, bytevec value) { key_->add(label, std::move(value)); }
+
+    bytevec encode() { return key_->canonicalize().encode(); }
+
+  private:
+    CoseKey(cppbor::Map* parsedKey) : key_(parsedKey) {}
+
+    // This is the full parsed key structure.
+    std::unique_ptr<cppbor::Map> key_;
+};
+
+ErrMsgOr<bytevec> generateCoseMac0Mac(const bytevec& macKey, const bytevec& externalAad,
+                                      const bytevec& payload);
+ErrMsgOr<cppbor::Array> constructCoseMac0(const bytevec& macKey, const bytevec& externalAad,
+                                          const bytevec& payload);
+ErrMsgOr<bytevec /* payload */> parseCoseMac0(const cppbor::Item* macItem);
+ErrMsgOr<bytevec /* payload */> verifyAndParseCoseMac0(const cppbor::Item* macItem,
+                                                       const bytevec& macKey);
+
+ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
+                                           const bytevec& payload, const bytevec& aad);
+ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, const bytevec& payload,
+                                           const bytevec& aad);
+ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, cppbor::Map extraProtectedFields,
+                                           const bytevec& payload, const bytevec& aad);
+/**
+ * Verify and parse a COSE_Sign1 message, returning the payload.
+ *
+ * @param ignoreSignature indicates whether signature verification should be skipped.  If true, no
+ *        verification of the signature will be done.
+ *
+ * @param coseSign1 is the COSE_Sign1 to verify and parse.
+ *
+ * @param signingCoseKey is a CBOR-encoded COSE_Key to use to verify the signature.  The bytevec may
+ *        be empty, in which case the function assumes that coseSign1's payload is the COSE_Key to
+ *        use, i.e. that coseSign1 is a self-signed "certificate".
+ */
+ErrMsgOr<bytevec /* payload */> verifyAndParseCoseSign1(bool ignoreSignature,
+                                                        const cppbor::Array* coseSign1,
+                                                        const bytevec& signingCoseKey,
+                                                        const bytevec& aad);
+
+ErrMsgOr<bytevec> createCoseEncryptCiphertext(const bytevec& key, const bytevec& nonce,
+                                              const bytevec& protectedParams, const bytevec& aad);
+ErrMsgOr<cppbor::Array> constructCoseEncrypt(const bytevec& key, const bytevec& nonce,
+                                             const bytevec& plaintextPayload, const bytevec& aad,
+                                             cppbor::Array recipients);
+ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>> getSenderPubKeyFromCoseEncrypt(
+        const cppbor::Item* encryptItem);
+inline ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>>
+getSenderPubKeyFromCoseEncrypt(const std::unique_ptr<cppbor::Item>& encryptItem) {
+    return getSenderPubKeyFromCoseEncrypt(encryptItem.get());
+}
+
+ErrMsgOr<bytevec /* plaintextPayload */> decryptCoseEncrypt(const bytevec& key,
+                                                            const cppbor::Item* encryptItem,
+                                                            const bytevec& aad);
+
+ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& senderPubKey, const bytevec& senderPrivKey,
+                                        const bytevec& recipientPubKey, bool senderIsA);
+
+ErrMsgOr<bytevec /* ciphertextWithTag */> aesGcmEncrypt(const bytevec& key, const bytevec& nonce,
+                                                        const bytevec& aad,
+                                                        const bytevec& plaintext);
+ErrMsgOr<bytevec /* plaintext */> aesGcmDecrypt(const bytevec& key, const bytevec& nonce,
+                                                const bytevec& aad,
+                                                const bytevec& ciphertextWithTag);
+
+}  // namespace cppcose
diff --git a/security/keymint/support/include/keymint_support/authorization_set.h b/security/keymint/support/include/keymint_support/authorization_set.h
index 6d36794..ca51b08 100644
--- a/security/keymint/support/include/keymint_support/authorization_set.h
+++ b/security/keymint/support/include/keymint_support/authorization_set.h
@@ -288,6 +288,7 @@
 
     AuthorizationSetBuilder& SigningKey();
     AuthorizationSetBuilder& EncryptionKey();
+    AuthorizationSetBuilder& AttestKey();
 
     AuthorizationSetBuilder& NoDigestOrPadding();
 
diff --git a/security/keymint/support/include/keymint_support/openssl_utils.h b/security/keymint/support/include/keymint_support/openssl_utils.h
index c3bc60b..a0212aa 100644
--- a/security/keymint/support/include/keymint_support/openssl_utils.h
+++ b/security/keymint/support/include/keymint_support/openssl_utils.h
@@ -34,13 +34,14 @@
     typedef std::unique_ptr<type, UniquePtrDeleter<type, type##_free>> type##_Ptr;
 
 MAKE_OPENSSL_PTR_TYPE(ASN1_OBJECT)
-MAKE_OPENSSL_PTR_TYPE(EC_KEY)
+MAKE_OPENSSL_PTR_TYPE(BN_CTX)
 MAKE_OPENSSL_PTR_TYPE(EC_GROUP)
+MAKE_OPENSSL_PTR_TYPE(EC_KEY)
 MAKE_OPENSSL_PTR_TYPE(EVP_PKEY)
 MAKE_OPENSSL_PTR_TYPE(EVP_PKEY_CTX)
 MAKE_OPENSSL_PTR_TYPE(RSA)
 MAKE_OPENSSL_PTR_TYPE(X509)
-MAKE_OPENSSL_PTR_TYPE(BN_CTX)
+MAKE_OPENSSL_PTR_TYPE(X509_NAME)
 
 typedef std::unique_ptr<BIGNUM, UniquePtrDeleter<BIGNUM, BN_free>> BIGNUM_Ptr;
 
diff --git a/security/keymint/support/include/remote_prov/remote_prov_utils.h b/security/keymint/support/include/remote_prov/remote_prov_utils.h
new file mode 100644
index 0000000..5e205a2
--- /dev/null
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <cppcose/cppcose.h>
+
+namespace aidl::android::hardware::security::keymint::remote_prov {
+
+using bytevec = std::vector<uint8_t>;
+using namespace cppcose;
+
+extern bytevec kTestMacKey;
+
+/**
+ * Generates random bytes.
+ */
+bytevec randomBytes(size_t numBytes);
+
+struct EekChain {
+    bytevec chain;
+    bytevec last_pubkey;
+    bytevec last_privkey;
+};
+
+/**
+ * Generates an X25518 EEK with the specified eekId and an Ed25519 chain of the
+ * specified length. All keys are generated randomly.
+ */
+ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId);
+
+struct BccEntryData {
+    bytevec pubKey;
+};
+
+/**
+ * Validates the provided CBOR-encoded BCC, returning a vector of BccEntryData
+ * structs containing the BCC entry contents.  If an entry contains no firmware
+ * digest, the corresponding BccEntryData.firmwareDigest will have length zero
+ * (there's no way to distinguish between an empty and missing firmware digest,
+ * which seems fine).
+ */
+ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc);
+
+}  // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
new file mode 100644
index 0000000..111cb30
--- /dev/null
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <remote_prov/remote_prov_utils.h>
+
+#include <openssl/rand.h>
+
+#include <cppbor.h>
+
+namespace aidl::android::hardware::security::keymint::remote_prov {
+
+bytevec kTestMacKey(32 /* count */, 0 /* byte value */);
+
+bytevec randomBytes(size_t numBytes) {
+    bytevec retval(numBytes);
+    RAND_bytes(retval.data(), numBytes);
+    return retval;
+}
+
+ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId) {
+    auto eekChain = cppbor::Array();
+
+    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());
+
+        // 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 */);
+        if (!coseSign1) return coseSign1.moveMessage();
+        eekChain.add(coseSign1.moveValue());
+    }
+
+    bytevec pub_key(X25519_PUBLIC_VALUE_LEN);
+    bytevec priv_key(X25519_PRIVATE_KEY_LEN);
+    X25519_keypair(pub_key.data(), priv_key.data());
+
+    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 */);
+    if (!coseSign1) return coseSign1.moveMessage();
+    eekChain.add(coseSign1.moveValue());
+
+    return EekChain{eekChain.encode(), pub_key, priv_key};
+}
+
+ErrMsgOr<bytevec> verifyAndParseCoseSign1Cwt(bool ignoreSignature, const cppbor::Array* coseSign1,
+                                             const bytevec& signingCoseKey, const bytevec& aad) {
+    if (!coseSign1 || coseSign1->size() != kCoseSign1EntryCount) {
+        return "Invalid COSE_Sign1";
+    }
+
+    const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
+    const cppbor::Bstr* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asBstr();
+    const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
+    const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
+
+    if (!protectedParams || !unprotectedParams || !payload || !signature) {
+        return "Invalid COSE_Sign1";
+    }
+
+    auto [parsedProtParams, _, errMsg] = cppbor::parse(protectedParams);
+    if (!parsedProtParams) {
+        return errMsg + " when parsing protected params.";
+    }
+    if (!parsedProtParams->asMap()) {
+        return "Protected params must be a map";
+    }
+
+    auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
+    if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != EDDSA) {
+        return "Unsupported signature algorithm";
+    }
+
+    // TODO(jbires): Handle CWTs as the CoseSign1 payload in a less hacky way. Since the CWT payload
+    //               is extremely remote provisioning specific, probably just make a separate
+    //               function there.
+    auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(payload);
+    if (!parsedPayload) return payloadErrMsg + " when parsing key";
+    if (!parsedPayload->asMap()) return "CWT must be a map";
+    auto serializedKey = parsedPayload->asMap()->get(-4670552)->clone();
+    if (!serializedKey || !serializedKey->asBstr()) return "Could not find key entry";
+
+    if (!ignoreSignature) {
+        bool selfSigned = signingCoseKey.empty();
+        auto key = CoseKey::parseEd25519(selfSigned ? serializedKey->asBstr()->value()
+                                                    : signingCoseKey);
+        if (!key) return "Bad signing key: " + key.moveMessage();
+
+        bytevec signatureInput = 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";
+        }
+    }
+
+    return serializedKey->asBstr()->value();
+}
+ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc) {
+    if (!bcc || bcc->size() == 0) return "Invalid BCC";
+
+    std::vector<BccEntryData> result;
+
+    bytevec prevKey;
+    // TODO(jbires): Actually process the pubKey at the start of the new bcc entry
+    for (size_t i = 1; i < bcc->size(); ++i) {
+        const cppbor::Array* entry = bcc->get(i)->asArray();
+        if (!entry || entry->size() != kCoseSign1EntryCount) {
+            return "Invalid BCC entry " + std::to_string(i) + ": " + prettyPrint(entry);
+        }
+        auto payload = verifyAndParseCoseSign1Cwt(false /* ignoreSignature */, entry,
+                                                  std::move(prevKey), bytevec{} /* AAD */);
+        if (!payload) {
+            return "Failed to verify entry " + std::to_string(i) + ": " + payload.moveMessage();
+        }
+
+        auto& certProtParms = entry->get(kCoseSign1ProtectedParams);
+        if (!certProtParms || !certProtParms->asBstr()) return "Invalid prot params";
+        auto [parsedProtParms, _, errMsg] = cppbor::parse(certProtParms->asBstr()->value());
+        if (!parsedProtParms || !parsedProtParms->asMap()) return "Invalid prot params";
+
+        result.push_back(BccEntryData{*payload});
+
+        // This entry's public key is the signing key for the next entry.
+        prevKey = payload.moveValue();
+    }
+
+    return result;
+}
+
+}  // namespace aidl::android::hardware::security::keymint::remote_prov
diff --git a/security/secureclock/aidl/vts/functional/Android.bp b/security/secureclock/aidl/vts/functional/Android.bp
index 30244eb..1619eab 100644
--- a/security/secureclock/aidl/vts/functional/Android.bp
+++ b/security/secureclock/aidl/vts/functional/Android.bp
@@ -33,8 +33,8 @@
         "libkeymint",
     ],
     static_libs: [
-        "android.hardware.security.keymint-unstable-ndk_platform",
-        "android.hardware.security.secureclock-unstable-ndk_platform",
+        "android.hardware.security.keymint-V1-ndk_platform",
+        "android.hardware.security.secureclock-V1-ndk_platform",
     ],
     test_suites: [
         "general-tests",
diff --git a/security/sharedsecret/aidl/vts/functional/Android.bp b/security/sharedsecret/aidl/vts/functional/Android.bp
index 56ab317..76bf7ff 100644
--- a/security/sharedsecret/aidl/vts/functional/Android.bp
+++ b/security/sharedsecret/aidl/vts/functional/Android.bp
@@ -33,8 +33,8 @@
         "libkeymint",
     ],
     static_libs: [
-        "android.hardware.security.keymint-unstable-ndk_platform",
-        "android.hardware.security.sharedsecret-unstable-ndk_platform",
+        "android.hardware.security.keymint-V1-ndk_platform",
+        "android.hardware.security.sharedsecret-V1-ndk_platform",
     ],
     test_suites: [
         "general-tests",
diff --git a/tv/cec/1.1/Android.bp b/tv/cec/1.1/Android.bp
new file mode 100644
index 0000000..c2d4e54
--- /dev/null
+++ b/tv/cec/1.1/Android.bp
@@ -0,0 +1,16 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.tv.cec@1.1",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "IHdmiCec.hal",
+        "IHdmiCecCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.tv.cec@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/tv/cec/1.1/IHdmiCec.hal b/tv/cec/1.1/IHdmiCec.hal
new file mode 100644
index 0000000..fe7bedf
--- /dev/null
+++ b/tv/cec/1.1/IHdmiCec.hal
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.cec@1.1;
+
+import @1.0::IHdmiCec;
+import @1.0::Result;
+import @1.0::SendMessageResult;
+
+import IHdmiCecCallback;
+
+/**
+ * HDMI-CEC HAL interface definition.
+ */
+interface IHdmiCec extends @1.0::IHdmiCec {
+    /**
+     * Passes the logical address that must be used in this system.
+     *
+     * HAL must use it to configure the hardware so that the CEC commands
+     * addressed the given logical address can be filtered in. This method must
+     * be able to be called as many times as necessary in order to support
+     * multiple logical devices.
+     *
+     * @param addr Logical address that must be used in this system. It must be
+     *        in the range of valid logical addresses for the call to succeed.
+     * @return result Result status of the operation. SUCCESS if successful,
+     *         FAILURE_INVALID_ARGS if the given logical address is invalid,
+     *         FAILURE_BUSY if device or resource is busy
+     */
+    addLogicalAddress_1_1(CecLogicalAddress addr) generates (Result result);
+
+    /**
+     * Transmits HDMI-CEC message to other HDMI device.
+     *
+     * The method must be designed to return in a certain amount of time and not
+     * hanging forever which may happen if CEC signal line is pulled low for
+     * some reason.
+     *
+     * It must try retransmission at least once as specified in the section '7.1
+     * Frame Re-transmissions' of the CEC Spec 1.4b.
+     *
+     * @param message CEC message to be sent to other HDMI device.
+     * @return result Result status of the operation. SUCCESS if successful,
+     *         NACK if the sent message is not acknowledged,
+     *         BUSY if the CEC bus is busy.
+     */
+    sendMessage_1_1(CecMessage message) generates (SendMessageResult result);
+
+    /**
+     * Sets a callback that HDMI-CEC HAL must later use for incoming CEC
+     * messages or internal HDMI events.
+     *
+     * @param callback Callback object to pass hdmi events to the system. The
+     *        previously registered callback must be replaced with this one.
+     */
+    setCallback_1_1(IHdmiCecCallback callback);
+};
diff --git a/tv/cec/1.1/IHdmiCecCallback.hal b/tv/cec/1.1/IHdmiCecCallback.hal
new file mode 100644
index 0000000..3928f18
--- /dev/null
+++ b/tv/cec/1.1/IHdmiCecCallback.hal
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.cec@1.1;
+
+import @1.0::IHdmiCecCallback;
+
+/**
+ * Callbacks from the HAL implementation to notify the system of new events.
+ */
+interface IHdmiCecCallback extends @1.0::IHdmiCecCallback {
+    /**
+     * The callback function that must be called by HAL implementation to notify
+     * the system of new CEC message arrival.
+     */
+    oneway onCecMessage_1_1(CecMessage message);
+};
diff --git a/tv/cec/1.1/default/Android.bp b/tv/cec/1.1/default/Android.bp
new file mode 100644
index 0000000..e0dff0d
--- /dev/null
+++ b/tv/cec/1.1/default/Android.bp
@@ -0,0 +1,23 @@
+cc_binary {
+    name: "android.hardware.tv.cec@1.1-service",
+    defaults: ["hidl_defaults"],
+    vintf_fragments: ["android.hardware.tv.cec@1.1-service.xml"],
+    relative_install_path: "hw",
+    vendor: true,
+    init_rc: ["android.hardware.tv.cec@1.1-service.rc"],
+    srcs: [
+        "serviceMock.cpp",
+        "HdmiCecMock.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libcutils",
+        "libbase",
+        "libutils",
+        "libhardware",
+        "libhidlbase",
+        "android.hardware.tv.cec@1.0",
+        "android.hardware.tv.cec@1.1",
+    ],
+}
diff --git a/tv/cec/1.1/default/HdmiCecMock.cpp b/tv/cec/1.1/default/HdmiCecMock.cpp
new file mode 100644
index 0000000..f65bab9
--- /dev/null
+++ b/tv/cec/1.1/default/HdmiCecMock.cpp
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.cec@1.1"
+#include <android-base/logging.h>
+#include <utils/Log.h>
+
+#include <hardware/hardware.h>
+#include <hardware/hdmi_cec.h>
+#include "HdmiCecMock.h"
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace cec {
+namespace V1_1 {
+namespace implementation {
+
+class WrappedCallback : public ::android::hardware::tv::cec::V1_1::IHdmiCecCallback {
+  public:
+    WrappedCallback(sp<::android::hardware::tv::cec::V1_0::IHdmiCecCallback> callback) {
+        mCallback = callback;
+    }
+
+    Return<void> onCecMessage(const ::android::hardware::tv::cec::V1_0::CecMessage& message) {
+        mCallback->onCecMessage(message);
+        return Void();
+    }
+    Return<void> onCecMessage_1_1(const ::android::hardware::tv::cec::V1_1::CecMessage& message) {
+        ::android::hardware::tv::cec::V1_0::CecMessage cecMessage;
+        cecMessage.initiator =
+                ::android::hardware::tv::cec::V1_0::CecLogicalAddress(message.initiator);
+        cecMessage.destination =
+                ::android::hardware::tv::cec::V1_0::CecLogicalAddress(message.destination);
+        cecMessage.body = message.body;
+        mCallback->onCecMessage(cecMessage);
+        return Void();
+    }
+    Return<void> onHotplugEvent(const ::android::hardware::tv::cec::V1_0::HotplugEvent& event) {
+        mCallback->onHotplugEvent(event);
+        return Void();
+    }
+
+  private:
+    sp<::android::hardware::tv::cec::V1_0::IHdmiCecCallback> mCallback;
+};
+
+/*
+ * (*set_option)() passes flags controlling the way HDMI-CEC service works down
+ * to HAL implementation. Those flags will be used in case the feature needs
+ * update in HAL itself, firmware or microcontroller.
+ */
+void HdmiCecMock::cec_set_option(int flag, int value) {
+    // maintain options and set them accordingly
+    switch (flag) {
+        case HDMI_OPTION_WAKEUP:
+            mOptionWakeUp = value;
+            break;
+        case HDMI_OPTION_ENABLE_CEC:
+            mOptionEnableCec = value;
+            break;
+        case HDMI_OPTION_SYSTEM_CEC_CONTROL:
+            mOptionSystemCecControl = value;
+            break;
+        case HDMI_OPTION_SET_LANG:
+            mOptionLanguage = value;
+            break;
+    }
+}
+
+// Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
+Return<Result> HdmiCecMock::addLogicalAddress(CecLogicalAddress addr) {
+    return addLogicalAddress_1_1(::android::hardware::tv::cec::V1_1::CecLogicalAddress(addr));
+}
+
+Return<void> HdmiCecMock::clearLogicalAddress() {
+    // remove logical address from the list
+    mLogicalAddresses = {};
+    return Void();
+}
+
+Return<void> HdmiCecMock::getPhysicalAddress(getPhysicalAddress_cb _hidl_cb) {
+    // maintain a physical address and return it
+    // default 0xFFFF, update on hotplug event
+    _hidl_cb(Result::SUCCESS, mPhysicalAddress);
+    return Void();
+}
+
+Return<SendMessageResult> HdmiCecMock::sendMessage(const CecMessage& message) {
+    ::android::hardware::tv::cec::V1_1::CecMessage cecMessage;
+    cecMessage.initiator = ::android::hardware::tv::cec::V1_1::CecLogicalAddress(message.initiator);
+    cecMessage.destination =
+            ::android::hardware::tv::cec::V1_1::CecLogicalAddress(message.destination);
+    cecMessage.body = message.body;
+    return sendMessage_1_1(cecMessage);
+}
+
+Return<void> HdmiCecMock::setCallback(const sp<IHdmiCecCallback>& callback) {
+    return setCallback_1_1(new WrappedCallback(callback));
+}
+
+Return<int32_t> HdmiCecMock::getCecVersion() {
+    // maintain a cec version and return it
+    return mCecVersion;
+}
+
+Return<uint32_t> HdmiCecMock::getVendorId() {
+    return mCecVendorId;
+}
+
+Return<void> HdmiCecMock::getPortInfo(getPortInfo_cb _hidl_cb) {
+    // TODO ready port info from device specific config
+    _hidl_cb(mPortInfo);
+    return Void();
+}
+
+Return<void> HdmiCecMock::setOption(OptionKey key, bool value) {
+    cec_set_option(static_cast<int>(key), value ? 1 : 0);
+    return Void();
+}
+
+Return<void> HdmiCecMock::setLanguage(const hidl_string& language) {
+    if (language.size() != 3) {
+        LOG(ERROR) << "Wrong language code: expected 3 letters, but it was " << language.size()
+                   << ".";
+        return Void();
+    }
+    // TODO validate if language is a valid language code
+    const char* languageStr = language.c_str();
+    int convertedLanguage = ((languageStr[0] & 0xFF) << 16) | ((languageStr[1] & 0xFF) << 8) |
+                            (languageStr[2] & 0xFF);
+    cec_set_option(HDMI_OPTION_SET_LANG, convertedLanguage);
+    return Void();
+}
+
+Return<void> HdmiCecMock::enableAudioReturnChannel(int32_t portId __unused, bool enable __unused) {
+    // Maintain ARC status
+    return Void();
+}
+
+Return<bool> HdmiCecMock::isConnected(int32_t portId) {
+    // maintain port connection status and update on hotplug event
+    if (portId < mTotalPorts && portId >= 0) {
+        return mPortConnectionStatus[portId];
+    }
+    return false;
+}
+
+// Methods from ::android::hardware::tv::cec::V1_1::IHdmiCec follow.
+Return<Result> HdmiCecMock::addLogicalAddress_1_1(
+        ::android::hardware::tv::cec::V1_1::CecLogicalAddress addr) {
+    // have a list to maintain logical addresses
+    int size = mLogicalAddresses.size();
+    mLogicalAddresses.resize(size + 1);
+    mLogicalAddresses[size + 1] = addr;
+    return Result::SUCCESS;
+}
+
+Return<SendMessageResult> HdmiCecMock::sendMessage_1_1(
+        const ::android::hardware::tv::cec::V1_1::CecMessage& message) {
+    if (message.body.size() == 0) {
+        return SendMessageResult::NACK;
+    }
+    sendMessageToFifo(message);
+    return SendMessageResult::SUCCESS;
+}
+
+Return<void> HdmiCecMock::setCallback_1_1(
+        const sp<::android::hardware::tv::cec::V1_1::IHdmiCecCallback>& callback) {
+    if (mCallback != nullptr) {
+        mCallback = nullptr;
+    }
+
+    if (callback != nullptr) {
+        mCallback = callback;
+        mCallback->linkToDeath(this, 0 /*cookie*/);
+
+        mInputFile = open(CEC_MSG_IN_FIFO, O_RDWR);
+        mOutputFile = open(CEC_MSG_OUT_FIFO, O_RDWR);
+        pthread_create(&mThreadId, NULL, __threadLoop, this);
+        pthread_setname_np(mThreadId, "hdmi_cec_loop");
+    }
+    return Void();
+}
+
+void* HdmiCecMock::__threadLoop(void* user) {
+    HdmiCecMock* const self = static_cast<HdmiCecMock*>(user);
+    self->threadLoop();
+    return 0;
+}
+
+int HdmiCecMock::readMessageFromFifo(unsigned char* buf, int msgCount) {
+    if (msgCount <= 0 || !buf) {
+        return 0;
+    }
+
+    int ret = -1;
+    /* maybe blocked at driver */
+    ret = read(mInputFile, buf, msgCount);
+    if (ret < 0) {
+        ALOGE("[halimp] read :%s failed, ret:%d\n", CEC_MSG_IN_FIFO, ret);
+        return -1;
+    }
+
+    return ret;
+}
+
+int HdmiCecMock::sendMessageToFifo(const ::android::hardware::tv::cec::V1_1::CecMessage& message) {
+    unsigned char msgBuf[CEC_MESSAGE_BODY_MAX_LENGTH];
+    int ret = -1;
+
+    memset(msgBuf, 0, sizeof(msgBuf));
+    msgBuf[0] = ((static_cast<uint8_t>(message.initiator) & 0xf) << 4) |
+                (static_cast<uint8_t>(message.destination) & 0xf);
+
+    size_t length = std::min(static_cast<size_t>(message.body.size()),
+                             static_cast<size_t>(MaxLength::MESSAGE_BODY));
+    for (size_t i = 0; i < length; ++i) {
+        msgBuf[i + 1] = static_cast<unsigned char>(message.body[i]);
+    }
+
+    // open the output pipe for writing outgoing cec message
+    mOutputFile = open(CEC_MSG_OUT_FIFO, O_WRONLY);
+    if (mOutputFile < 0) {
+        ALOGD("[halimp] file open failed for writing");
+        return -1;
+    }
+
+    // write message into the output pipe
+    ret = write(mOutputFile, msgBuf, length + 1);
+    close(mOutputFile);
+    if (ret < 0) {
+        ALOGE("[halimp] write :%s failed, ret:%d\n", CEC_MSG_OUT_FIFO, ret);
+        return -1;
+    }
+    return ret;
+}
+
+void HdmiCecMock::printCecMsgBuf(const char* msg_buf, int len) {
+    char buf[64] = {};
+    int i, size = 0;
+    memset(buf, 0, sizeof(buf));
+    for (i = 0; i < len; i++) {
+        size += sprintf(buf + size, " %02x", msg_buf[i]);
+    }
+    ALOGD("[halimp] %s, msg:%s", __FUNCTION__, buf);
+}
+
+void HdmiCecMock::handleHotplugMessage(unsigned char* msgBuf) {
+    HotplugEvent hotplugEvent{.connected = ((msgBuf[3]) & 0xf) > 0,
+                              .portId = static_cast<uint32_t>(msgBuf[0] & 0xf)};
+
+    if (hotplugEvent.portId >= mPortInfo.size()) {
+        ALOGD("[halimp] ignore hot plug message, id %x does not exist", hotplugEvent.portId);
+        return;
+    }
+
+    ALOGD("[halimp] hot plug port id %x, is connected %x", (msgBuf[0] & 0xf), (msgBuf[3] & 0xf));
+    if (mPortInfo[hotplugEvent.portId].type == HdmiPortType::OUTPUT) {
+        mPhysicalAddress =
+                ((hotplugEvent.connected == 0) ? 0xffff : ((msgBuf[1] << 8) | (msgBuf[2])));
+        mPortInfo[hotplugEvent.portId].physicalAddress = mPhysicalAddress;
+        ALOGD("[halimp] hot plug physical address %x", mPhysicalAddress);
+    }
+
+    // todo update connection status
+
+    if (mCallback != nullptr) {
+        mCallback->onHotplugEvent(hotplugEvent);
+    }
+}
+
+void HdmiCecMock::handleCecMessage(unsigned char* msgBuf, int megSize) {
+    ::android::hardware::tv::cec::V1_1::CecMessage message;
+    size_t length = std::min(static_cast<size_t>(megSize - 1),
+                             static_cast<size_t>(MaxLength::MESSAGE_BODY));
+    message.body.resize(length);
+
+    for (size_t i = 0; i < length; ++i) {
+        message.body[i] = static_cast<uint8_t>(msgBuf[i + 1]);
+        ALOGD("[halimp] msg body %x", message.body[i]);
+    }
+
+    message.initiator = static_cast<::android::hardware::tv::cec::V1_1::CecLogicalAddress>(
+            (msgBuf[0] >> 4) & 0xf);
+    ALOGD("[halimp] msg init %x", message.initiator);
+    message.destination = static_cast<::android::hardware::tv::cec::V1_1::CecLogicalAddress>(
+            (msgBuf[0] >> 0) & 0xf);
+    ALOGD("[halimp] msg dest %x", message.destination);
+
+    // messageValidateAndHandle(&event);
+
+    if (mCallback != nullptr) {
+        mCallback->onCecMessage_1_1(message);
+    }
+}
+
+void HdmiCecMock::threadLoop() {
+    ALOGD("[halimp] threadLoop start.");
+    unsigned char msgBuf[CEC_MESSAGE_BODY_MAX_LENGTH];
+    int r = -1;
+
+    // open the input pipe
+    while (mInputFile < 0) {
+        usleep(1000 * 1000);
+        mInputFile = open(CEC_MSG_IN_FIFO, O_RDONLY);
+    }
+    ALOGD("[halimp] file open ok, fd = %d.", mInputFile);
+
+    while (mCecThreadRun) {
+        if (!mOptionSystemCecControl) {
+            usleep(1000 * 1000);
+            continue;
+        }
+
+        memset(msgBuf, 0, sizeof(msgBuf));
+        // try to get a message from dev.
+        // echo -n -e '\x04\x83' >> /dev/cec
+        r = readMessageFromFifo(msgBuf, CEC_MESSAGE_BODY_MAX_LENGTH);
+        if (r <= 1) {
+            // ignore received ping messages
+            continue;
+        }
+
+        printCecMsgBuf((const char*)msgBuf, r);
+
+        if (((msgBuf[0] >> 4) & 0xf) == 0xf) {
+            // the message is a hotplug event
+            handleHotplugMessage(msgBuf);
+            continue;
+        }
+
+        handleCecMessage(msgBuf, r);
+    }
+
+    ALOGD("[halimp] thread end.");
+    // mCecDevice.mExited = true;
+}
+
+HdmiCecMock::HdmiCecMock() {
+    ALOGE("[halimp] Opening a virtual HAL for testing and virtual machine.");
+    mCallback = nullptr;
+    mPortInfo.resize(mTotalPorts);
+    mPortConnectionStatus.resize(mTotalPorts);
+    mPortInfo[0] = {.type = HdmiPortType::OUTPUT,
+                    .portId = static_cast<uint32_t>(1),
+                    .cecSupported = true,
+                    .arcSupported = false,
+                    .physicalAddress = mPhysicalAddress};
+    mPortConnectionStatus[0] = false;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cec
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/tv/cec/1.1/default/HdmiCecMock.h b/tv/cec/1.1/default/HdmiCecMock.h
new file mode 100644
index 0000000..0205f8d
--- /dev/null
+++ b/tv/cec/1.1/default/HdmiCecMock.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware/tv/cec/1.1/IHdmiCec.h>
+#include <hidl/Status.h>
+#include <algorithm>
+#include <vector>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace cec {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::tv::cec::V1_0::CecLogicalAddress;
+using ::android::hardware::tv::cec::V1_0::CecMessage;
+using ::android::hardware::tv::cec::V1_0::HdmiPortInfo;
+using ::android::hardware::tv::cec::V1_0::HdmiPortType;
+using ::android::hardware::tv::cec::V1_0::HotplugEvent;
+using ::android::hardware::tv::cec::V1_0::IHdmiCecCallback;
+using ::android::hardware::tv::cec::V1_0::MaxLength;
+using ::android::hardware::tv::cec::V1_0::OptionKey;
+using ::android::hardware::tv::cec::V1_0::Result;
+using ::android::hardware::tv::cec::V1_0::SendMessageResult;
+using ::android::hardware::tv::cec::V1_1::IHdmiCec;
+
+#define CEC_MSG_IN_FIFO "/dev/cec_in_pipe"
+#define CEC_MSG_OUT_FIFO "/dev/cec_out_pipe"
+
+struct HdmiCecMock : public IHdmiCec, public hidl_death_recipient {
+    HdmiCecMock();
+    // Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
+    Return<Result> addLogicalAddress(CecLogicalAddress addr) override;
+    Return<void> clearLogicalAddress() override;
+    Return<void> getPhysicalAddress(getPhysicalAddress_cb _hidl_cb) override;
+    Return<SendMessageResult> sendMessage(const CecMessage& message) override;
+    Return<void> setCallback(
+            const sp<::android::hardware::tv::cec::V1_0::IHdmiCecCallback>& callback) override;
+    Return<int32_t> getCecVersion() override;
+    Return<uint32_t> getVendorId() override;
+    Return<void> getPortInfo(getPortInfo_cb _hidl_cb) override;
+    Return<void> setOption(OptionKey key, bool value) override;
+    Return<void> setLanguage(const hidl_string& language) override;
+    Return<void> enableAudioReturnChannel(int32_t portId, bool enable) override;
+    Return<bool> isConnected(int32_t portId) override;
+
+    // Methods from ::android::hardware::tv::cec::V1_1::IHdmiCec follow.
+    Return<Result> addLogicalAddress_1_1(
+            ::android::hardware::tv::cec::V1_1::CecLogicalAddress addr) override;
+    Return<SendMessageResult> sendMessage_1_1(
+            const ::android::hardware::tv::cec::V1_1::CecMessage& message) override;
+    Return<void> setCallback_1_1(
+            const sp<::android::hardware::tv::cec::V1_1::IHdmiCecCallback>& callback) override;
+
+    virtual void serviceDied(uint64_t /*cookie*/,
+                             const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+        setCallback(nullptr);
+    }
+
+    void cec_set_option(int flag, int value);
+    void printCecMsgBuf(const char* msg_buf, int len);
+
+  private:
+    static void* __threadLoop(void* data);
+    void threadLoop();
+    int readMessageFromFifo(unsigned char* buf, int msgCount);
+    int sendMessageToFifo(const ::android::hardware::tv::cec::V1_1::CecMessage& message);
+    void handleHotplugMessage(unsigned char* msgBuf);
+    void handleCecMessage(unsigned char* msgBuf, int length);
+
+  private:
+    sp<::android::hardware::tv::cec::V1_1::IHdmiCecCallback> mCallback;
+
+    // Variables for the virtual cec hal impl
+    uint16_t mPhysicalAddress = 0xFFFF;
+    vector<::android::hardware::tv::cec::V1_1::CecLogicalAddress> mLogicalAddresses;
+    int32_t mCecVersion = 0x06;
+    uint32_t mCecVendorId = 0x01;
+
+    // Port configuration
+    int mTotalPorts = 1;
+    hidl_vec<HdmiPortInfo> mPortInfo;
+    hidl_vec<bool> mPortConnectionStatus;
+
+    // CEC Option value
+    int mOptionWakeUp = 0;
+    int mOptionEnableCec = 0;
+    int mOptionSystemCecControl = 0;
+    int mOptionLanguage = 0;
+
+    // Testing variables
+    // Input file descriptor
+    int mInputFile;
+    // Output file descriptor
+    int mOutputFile;
+    bool mCecThreadRun = true;
+    pthread_t mThreadId = 0;
+};
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace cec
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/tv/cec/1.1/default/android.hardware.tv.cec@1.1-service.rc b/tv/cec/1.1/default/android.hardware.tv.cec@1.1-service.rc
new file mode 100644
index 0000000..e150c91
--- /dev/null
+++ b/tv/cec/1.1/default/android.hardware.tv.cec@1.1-service.rc
@@ -0,0 +1,6 @@
+service vendor.cec-hal-1-1 /vendor/bin/hw/android.hardware.tv.cec@1.1-service
+    interface android.hardware.tv.cec@1.0::IHdmiCec default
+    interface android.hardware.tv.cec@1.1::IHdmiCec default
+    class hal
+    user system
+    group system
\ No newline at end of file
diff --git a/tv/cec/1.1/default/android.hardware.tv.cec@1.1-service.xml b/tv/cec/1.1/default/android.hardware.tv.cec@1.1-service.xml
new file mode 100644
index 0000000..492369e
--- /dev/null
+++ b/tv/cec/1.1/default/android.hardware.tv.cec@1.1-service.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.tv.cec</name>
+        <transport>hwbinder</transport>
+        <version>1.1</version>
+        <interface>
+            <name>IHdmiCec</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/tv/cec/1.1/default/serviceMock.cpp b/tv/cec/1.1/default/serviceMock.cpp
new file mode 100644
index 0000000..72fc311
--- /dev/null
+++ b/tv/cec/1.1/default/serviceMock.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.cec@1.1-service-shim"
+
+#include <android/hardware/tv/cec/1.1/IHdmiCec.h>
+#include <hidl/LegacySupport.h>
+#include "HdmiCecMock.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::tv::cec::V1_1::IHdmiCec;
+using android::hardware::tv::cec::V1_1::implementation::HdmiCecMock;
+
+int main() {
+    configureRpcThreadpool(8, true /* callerWillJoin */);
+
+    // Setup hwbinder service
+    android::sp<IHdmiCec> service = new HdmiCecMock();
+    android::status_t status;
+    status = service->registerAsService();
+    LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering mock cec service: %d",
+                        status);
+
+    joinRpcThreadpool();
+    return 0;
+}
diff --git a/tv/cec/1.1/types.hal b/tv/cec/1.1/types.hal
new file mode 100644
index 0000000..a117519
--- /dev/null
+++ b/tv/cec/1.1/types.hal
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.cec@1.1;
+
+import @1.0::CecLogicalAddress;
+import @1.0::CecMessageType;
+
+enum CecLogicalAddress : @1.0::CecLogicalAddress {
+    BACKUP_1 = 12,
+    BACKUP_2 = 13,
+};
+
+enum CecMessageType : @1.0::CecMessageType {
+    GIVE_FEATURES = 0xA5,
+    REPORT_FEATURES = 0xA6,
+    REQUEST_CURRENT_LATENCY = 0xA7,
+    REPORT_CURRENT_LATENCY = 0xA8,
+};
+
+struct CecMessage {
+    /** logical address of the initiator */
+    CecLogicalAddress initiator;
+
+    /** logical address of destination */
+    CecLogicalAddress destination;
+
+    /**
+     * The maximum size of body is 15 (MaxLength::MESSAGE_BODY) as specified in
+     * the section 6 of the CEC Spec 1.4b. Overflowed data must be ignored. */
+    vec<uint8_t> body;
+};
diff --git a/tv/cec/1.1/vts/functional/Android.bp b/tv/cec/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..5fc7093
--- /dev/null
+++ b/tv/cec/1.1/vts/functional/Android.bp
@@ -0,0 +1,14 @@
+cc_test {
+    name: "VtsHalTvCecV1_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalTvCecV1_1TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.tv.cec@1.1",
+        "android.hardware.tv.cec@1.0",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    disable_framework: true,
+}
diff --git a/tv/cec/1.1/vts/functional/VtsHalTvCecV1_1TargetTest.cpp b/tv/cec/1.1/vts/functional/VtsHalTvCecV1_1TargetTest.cpp
new file mode 100644
index 0000000..1eb4643
--- /dev/null
+++ b/tv/cec/1.1/vts/functional/VtsHalTvCecV1_1TargetTest.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "HdmiCec_hal_test"
+#include <android-base/logging.h>
+
+#include <android/hardware/tv/cec/1.1/IHdmiCec.h>
+#include <android/hardware/tv/cec/1.1/types.h>
+#include <utils/Log.h>
+#include <sstream>
+#include <vector>
+
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_death_recipient;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::tv::cec::V1_0::CecDeviceType;
+using ::android::hardware::tv::cec::V1_0::HdmiPortInfo;
+using ::android::hardware::tv::cec::V1_0::HdmiPortType;
+using ::android::hardware::tv::cec::V1_0::HotplugEvent;
+using ::android::hardware::tv::cec::V1_0::OptionKey;
+using ::android::hardware::tv::cec::V1_0::Result;
+using ::android::hardware::tv::cec::V1_0::SendMessageResult;
+using ::android::hardware::tv::cec::V1_1::CecLogicalAddress;
+using ::android::hardware::tv::cec::V1_1::CecMessage;
+using ::android::hardware::tv::cec::V1_1::IHdmiCec;
+using ::android::hardware::tv::cec::V1_1::IHdmiCecCallback;
+
+#define CEC_VERSION 0x05
+#define INCORRECT_VENDOR_ID 0x00
+
+// The main test class for TV CEC HAL.
+class HdmiCecTest : public ::testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        hdmiCec = IHdmiCec::getService(GetParam());
+        ASSERT_NE(hdmiCec, nullptr);
+        ALOGI("%s: getService() for hdmiCec is %s", __func__,
+              hdmiCec->isRemote() ? "remote" : "local");
+
+        hdmiCec_death_recipient = new HdmiCecDeathRecipient();
+        hdmiCecCallback = new CecCallback();
+        ASSERT_NE(hdmiCec_death_recipient, nullptr);
+        ASSERT_TRUE(hdmiCec->linkToDeath(hdmiCec_death_recipient, 0).isOk());
+    }
+
+    std::vector<int> getDeviceTypes() {
+        std::vector<int> deviceTypes;
+        FILE* p = popen("getprop ro.hdmi.device_type", "re");
+        if (p) {
+            char* line = NULL;
+            size_t len = 0;
+            if (getline(&line, &len, p) > 0) {
+                std::istringstream stream(line);
+                std::string number{};
+                while (std::getline(stream, number, ',')) {
+                    deviceTypes.push_back(stoi(number));
+                }
+            }
+            pclose(p);
+        }
+        return deviceTypes;
+    }
+
+    bool hasDeviceType(CecDeviceType type) {
+        std::vector<int> deviceTypes = getDeviceTypes();
+        return std::find(deviceTypes.begin(), deviceTypes.end(), (int)type) != deviceTypes.end();
+    }
+
+    class CecCallback : public IHdmiCecCallback {
+      public:
+        Return<void> onCecMessage(
+                const ::android::hardware::tv::cec::V1_0::CecMessage& /* message */) {
+            return Void();
+        }
+        Return<void> onCecMessage_1_1(
+                const ::android::hardware::tv::cec::V1_1::CecMessage& /* message */) {
+            return Void();
+        }
+        Return<void> onHotplugEvent(
+                const ::android::hardware::tv::cec::V1_0::HotplugEvent& /* event */) {
+            return Void();
+        }
+    };
+
+    class HdmiCecDeathRecipient : public hidl_death_recipient {
+      public:
+        void serviceDied(uint64_t /*cookie*/,
+                         const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) override {
+            FAIL();
+        }
+    };
+
+    sp<IHdmiCec> hdmiCec;
+    sp<IHdmiCecCallback> hdmiCecCallback;
+    sp<HdmiCecDeathRecipient> hdmiCec_death_recipient;
+};
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HdmiCecTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, HdmiCecTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IHdmiCec::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+TEST_P(HdmiCecTest, ClearAddLogicalAddress) {
+    hdmiCec->clearLogicalAddress();
+    Return<Result> ret = hdmiCec->addLogicalAddress_1_1(CecLogicalAddress::PLAYBACK_3);
+    EXPECT_EQ(ret, Result::SUCCESS);
+}
+
+TEST_P(HdmiCecTest, SendMessage) {
+    CecMessage message;
+    message.initiator = CecLogicalAddress::PLAYBACK_1;
+    message.destination = CecLogicalAddress::BROADCAST;
+    message.body.resize(1);
+    message.body[0] = 131;
+    SendMessageResult ret = hdmiCec->sendMessage_1_1(message);
+    EXPECT_EQ(ret, SendMessageResult::SUCCESS);
+}
+
+TEST_P(HdmiCecTest, CecVersion) {
+    Return<int32_t> ret = hdmiCec->getCecVersion();
+    EXPECT_GE(ret, CEC_VERSION);
+}
+
+TEST_P(HdmiCecTest, SetCallback) {
+    Return<void> ret = hdmiCec->setCallback_1_1(new CecCallback());
+    ASSERT_TRUE(ret.isOk());
+}
+
+TEST_P(HdmiCecTest, VendorId) {
+    Return<uint32_t> ret = hdmiCec->getVendorId();
+    EXPECT_NE(ret, INCORRECT_VENDOR_ID);
+}
+
+TEST_P(HdmiCecTest, GetPortInfo) {
+    hidl_vec<HdmiPortInfo> ports;
+    Return<void> ret =
+            hdmiCec->getPortInfo([&ports](hidl_vec<HdmiPortInfo> list) { ports = list; });
+    ASSERT_TRUE(ret.isOk());
+    bool cecSupportedOnDevice = false;
+    for (size_t i = 0; i < ports.size(); ++i) {
+        EXPECT_TRUE((ports[i].type == HdmiPortType::OUTPUT) ||
+                    (ports[i].type == HdmiPortType::INPUT));
+        if (ports[i].portId == 0) {
+            ALOGW("%s: Port id should start from 1", __func__);
+        }
+        cecSupportedOnDevice = cecSupportedOnDevice | ports[i].cecSupported;
+    }
+    EXPECT_NE(cecSupportedOnDevice, false) << "At least one port should support CEC";
+}
+
+TEST_P(HdmiCecTest, SetOption) {
+    Return<void> wakeup = hdmiCec->setOption(OptionKey::WAKEUP, false);
+    ASSERT_TRUE(wakeup.isOk());
+    Return<void> enableCec = hdmiCec->setOption(OptionKey::ENABLE_CEC, false);
+    ASSERT_TRUE(enableCec.isOk());
+    Return<void> systemCecControl = hdmiCec->setOption(OptionKey::SYSTEM_CEC_CONTROL, true);
+    ASSERT_TRUE(systemCecControl.isOk());
+    // Restore option keys to their default values
+    hdmiCec->setOption(OptionKey::WAKEUP, true);
+    hdmiCec->setOption(OptionKey::ENABLE_CEC, true);
+    hdmiCec->setOption(OptionKey::SYSTEM_CEC_CONTROL, false);
+}
+
+TEST_P(HdmiCecTest, SetLanguage) {
+    Return<void> ret = hdmiCec->setLanguage("eng");
+    ASSERT_TRUE(ret.isOk());
+}
+
+TEST_P(HdmiCecTest, EnableAudioReturnChannel) {
+    hidl_vec<HdmiPortInfo> ports;
+    Return<void> ret =
+            hdmiCec->getPortInfo([&ports](hidl_vec<HdmiPortInfo> list) { ports = list; });
+    for (size_t i = 0; i < ports.size(); ++i) {
+        if (ports[i].arcSupported) {
+            Return<void> ret = hdmiCec->enableAudioReturnChannel(ports[i].portId, true);
+            ASSERT_TRUE(ret.isOk());
+        }
+    }
+}
\ No newline at end of file
diff --git a/wifi/1.5/IWifiChip.hal b/wifi/1.5/IWifiChip.hal
index 209190a..5a3e288 100644
--- a/wifi/1.5/IWifiChip.hal
+++ b/wifi/1.5/IWifiChip.hal
@@ -236,19 +236,54 @@
     setCountryCode(int8_t[2] code) generates (WifiStatus status);
 
     /**
+     * Usable Wifi channels filter masks.
+     */
+    enum UsableChannelFilter : uint32_t {
+        /**
+         * Filter Wifi channels that should be avoided due to extreme
+         * cellular coexistence restrictions. Some Wifi channels can have
+         * extreme interference from/to cellular due to short frequency
+         * seperation with neighboring cellular channels or when there
+         * is harmonic and intermodulation interference. Channels which
+         * only have some performance degradation (e.g. power back off is
+         * sufficient to deal with coexistence issue) can be included and
+         * should not be filtered out.
+         */
+        CELLULAR_COEXISTENCE = 1 << 0,
+        /**
+         * Filter based on concurrency state.
+         * Examples:
+         * - 5GHz SAP operation may be supported in standalone mode, but if
+         *  there is STA connection on 5GHz DFS channel, none of the 5GHz
+         *  channels are usable for SAP if device does not support DFS SAP mode.
+         * - P2P GO may not be supported on indoor channels in EU during
+         *  standalone mode but if there is a STA connection on indoor channel,
+         *  P2P GO may be supported by some vendors on the same STA channel.
+         */
+        CONCURRENCY = 1 << 1,
+    };
+
+    /**
      * Retrieve list of usable Wifi channels for the specified band &
      * operational modes.
      *
      * The list of usable Wifi channels in a given band depends on factors
-     * like current country code, operational mode (e.g. STA, SAP, CLI, GO,
-     * TDLS, NAN) and any hard restrictons due to DFS, LTE Coex and
-     * MCC(multi channel-concurrency).
+     * like current country code, operational mode (e.g. STA, SAP, WFD-CLI,
+     * WFD-GO, TDLS, NAN) and other restrictons due to DFS, cellular coexistence
+     * and conncurency state of the device.
      *
      * @param band |WifiBand| for which list of usable channels is requested.
      * @param ifaceModeMask Bitmask of the modes represented by |WifiIfaceMode|
      *        Bitmask respresents all the modes that the caller is interested
-     *        in (e.g. STA, SAP, CLI, GO, TDLS, NAN).
-     *        Note: Bitmask does not represent concurrency matrix.
+     *        in (e.g. STA, SAP, CLI, GO, TDLS, NAN). E.g. If the caller is
+     *        interested in knowing usable channels for P2P CLI, P2P GO & NAN,
+     *        ifaceModeMask would be set to
+     *        IFACE_MODE_P2P_CLIENT|IFACE_MODE_P2P_GO|IFACE_MODE_NAN.
+     * @param filterMask Bitmask of filters represented by
+     *        |UsableChannelFilter|. Specifies whether driver should filter
+     *        channels based on additional criteria. If no filter is specified
+     *        driver should return usable channels purely based on regulatory
+     *        constraints.
      * @return status WifiStatus of the operation.
      *         Possible status codes:
      *         |WifiStatusCode.SUCCESS|,
@@ -257,10 +292,15 @@
      *         |WifiStatusCode.FAILURE_UNKNOWN|
      * @return channels List of channels represented by |WifiUsableChannel|
      *         Each entry represents a channel frequency, bandwidth and
-     *         bitmask of operational modes (e.g. STA, SAP, CLI, GO, TDLS, NAN)
-     *         allowed on that channel.
-     *         Note: Bitmask does not represent concurrency matrix.
+     *         bitmask of modes (e.g. STA, SAP, CLI, GO, TDLS, NAN) that are
+     *         allowed on that channel. E.g. If only STA mode can be supported
+     *         on an indoor channel, only the IFACE_MODE_STA bit would be set
+     *         for that channel. If 5GHz SAP cannot be supported, then none of
+     *         the 5GHz channels will have IFACE_MODE_SOFTAP bit set.
+     *         Note: Bits do not represent concurrency state. Each bit only
+     *         represents whether particular mode is allowed on that channel.
      */
-    getUsableChannels(WifiBand band, bitfield<WifiIfaceMode> ifaceModeMask)
+    getUsableChannels(WifiBand band, bitfield<WifiIfaceMode> ifaceModeMask,
+            bitfield<UsableChannelFilter> filterMask)
         generates (WifiStatus status, vec<WifiUsableChannel> channels);
 };
diff --git a/wifi/1.5/default/hidl_struct_util.cpp b/wifi/1.5/default/hidl_struct_util.cpp
index 7cee4cd..3c69da5 100644
--- a/wifi/1.5/default/hidl_struct_util.cpp
+++ b/wifi/1.5/default/hidl_struct_util.cpp
@@ -445,6 +445,20 @@
     return hidl_iface_mask;
 }
 
+uint32_t convertHidlUsableChannelFilterToLegacy(uint32_t hidl_filter_mask) {
+    uint32_t legacy_filter_mask = 0;
+    if (hidl_filter_mask &
+        IWifiChip::UsableChannelFilter::CELLULAR_COEXISTENCE) {
+        legacy_filter_mask |=
+            legacy_hal::WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE;
+    }
+    if (hidl_filter_mask & IWifiChip::UsableChannelFilter::CONCURRENCY) {
+        legacy_filter_mask |=
+            legacy_hal::WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY;
+    }
+    return legacy_filter_mask;
+}
+
 bool convertLegacyWifiUsableChannelToHidl(
     const legacy_hal::wifi_usable_channel& legacy_usable_channel,
     V1_5::WifiUsableChannel* hidl_usable_channel) {
diff --git a/wifi/1.5/default/hidl_struct_util.h b/wifi/1.5/default/hidl_struct_util.h
index c0d7bf8..8b81033 100644
--- a/wifi/1.5/default/hidl_struct_util.h
+++ b/wifi/1.5/default/hidl_struct_util.h
@@ -208,6 +208,7 @@
     std::vector<V1_4::RttResult>* hidl_results);
 uint32_t convertHidlWifiBandToLegacyMacBand(V1_5::WifiBand band);
 uint32_t convertHidlWifiIfaceModeToLegacy(uint32_t hidl_iface_mask);
+uint32_t convertHidlUsableChannelFilterToLegacy(uint32_t hidl_filter_mask);
 bool convertLegacyWifiUsableChannelsToHidl(
     const std::vector<legacy_hal::wifi_usable_channel>& legacy_usable_channels,
     std::vector<V1_5::WifiUsableChannel>* hidl_usable_channels);
diff --git a/wifi/1.5/default/wifi_chip.cpp b/wifi/1.5/default/wifi_chip.cpp
index 2dc7314..0450a7b 100644
--- a/wifi/1.5/default/wifi_chip.cpp
+++ b/wifi/1.5/default/wifi_chip.cpp
@@ -740,10 +740,11 @@
 
 Return<void> WifiChip::getUsableChannels(
     WifiBand band, hidl_bitfield<WifiIfaceMode> ifaceModeMask,
+    hidl_bitfield<UsableChannelFilter> filterMask,
     getUsableChannels_cb _hidl_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
                            &WifiChip::getUsableChannelsInternal, _hidl_cb, band,
-                           ifaceModeMask);
+                           ifaceModeMask, filterMask);
 }
 
 void WifiChip::invalidateAndRemoveAllIfaces() {
@@ -1500,13 +1501,17 @@
 }
 
 std::pair<WifiStatus, std::vector<WifiUsableChannel>>
-WifiChip::getUsableChannelsInternal(WifiBand band, uint32_t ifaceModeMask) {
+WifiChip::getUsableChannelsInternal(WifiBand band, uint32_t ifaceModeMask,
+                                    uint32_t filterMask) {
     legacy_hal::wifi_error legacy_status;
     std::vector<legacy_hal::wifi_usable_channel> legacy_usable_channels;
     std::tie(legacy_status, legacy_usable_channels) =
         legacy_hal_.lock()->getUsableChannels(
             hidl_struct_util::convertHidlWifiBandToLegacyMacBand(band),
-            hidl_struct_util::convertHidlWifiIfaceModeToLegacy(ifaceModeMask));
+            hidl_struct_util::convertHidlWifiIfaceModeToLegacy(ifaceModeMask),
+            hidl_struct_util::convertHidlUsableChannelFilterToLegacy(
+                filterMask));
+
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
         return {createWifiStatusFromLegacyError(legacy_status), {}};
     }
diff --git a/wifi/1.5/default/wifi_chip.h b/wifi/1.5/default/wifi_chip.h
index d542792..b4ed30e 100644
--- a/wifi/1.5/default/wifi_chip.h
+++ b/wifi/1.5/default/wifi_chip.h
@@ -180,9 +180,10 @@
         setCoexUnsafeChannels_cb hidl_status_cb) override;
     Return<void> setCountryCode(const hidl_array<int8_t, 2>& code,
                                 setCountryCode_cb _hidl_cb) override;
-    Return<void> getUsableChannels(WifiBand band,
-                                   hidl_bitfield<WifiIfaceMode> ifaceModeMask,
-                                   getUsableChannels_cb _hidl_cb) override;
+    Return<void> getUsableChannels(
+        WifiBand band, hidl_bitfield<WifiIfaceMode> ifaceModeMask,
+        hidl_bitfield<UsableChannelFilter> filterMask,
+        getUsableChannels_cb _hidl_cb) override;
 
    private:
     void invalidateAndRemoveAllIfaces();
@@ -265,7 +266,8 @@
         std::vector<CoexUnsafeChannel> unsafe_channels, uint32_t restrictions);
     WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
     std::pair<WifiStatus, std::vector<WifiUsableChannel>>
-    getUsableChannelsInternal(WifiBand band, uint32_t ifaceModeMask);
+    getUsableChannelsInternal(WifiBand band, uint32_t ifaceModeMask,
+                              uint32_t filterMask);
     WifiStatus handleChipConfiguration(
         std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
     WifiStatus registerDebugRingBufferCallback();
diff --git a/wifi/1.5/default/wifi_legacy_hal.cpp b/wifi/1.5/default/wifi_legacy_hal.cpp
index 94603b3..f5ca753 100644
--- a/wifi/1.5/default/wifi_legacy_hal.cpp
+++ b/wifi/1.5/default/wifi_legacy_hal.cpp
@@ -1638,12 +1638,14 @@
 }
 
 std::pair<wifi_error, std::vector<wifi_usable_channel>>
-WifiLegacyHal::getUsableChannels(uint32_t band_mask, uint32_t iface_mode_mask) {
+WifiLegacyHal::getUsableChannels(uint32_t band_mask, uint32_t iface_mode_mask,
+                                 uint32_t filter_mask) {
     std::vector<wifi_usable_channel> channels;
     channels.resize(kMaxWifiUsableChannels);
     uint32_t size = 0;
     wifi_error status = global_func_table_.wifi_get_usable_channels(
-        global_handle_, band_mask, iface_mode_mask, channels.size(), &size,
+        global_handle_, band_mask, iface_mode_mask, filter_mask,
+        channels.size(), &size,
         reinterpret_cast<wifi_usable_channel*>(channels.data()));
     CHECK(size >= 0 && size <= kMaxWifiUsableChannels);
     channels.resize(size);
diff --git a/wifi/1.5/default/wifi_legacy_hal.h b/wifi/1.5/default/wifi_legacy_hal.h
index dc641ae..03ca841 100644
--- a/wifi/1.5/default/wifi_legacy_hal.h
+++ b/wifi/1.5/default/wifi_legacy_hal.h
@@ -313,6 +313,8 @@
 using ::wifi_tx_packet_fate;
 using ::wifi_tx_report;
 using ::wifi_usable_channel;
+using ::WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE;
+using ::WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY;
 using ::WLAN_MAC_2_4_BAND;
 using ::WLAN_MAC_5_0_BAND;
 using ::WLAN_MAC_60_0_BAND;
@@ -705,7 +707,7 @@
     // Retrieve the list of usable channels in the requested bands
     // for the requested modes
     std::pair<wifi_error, std::vector<wifi_usable_channel>> getUsableChannels(
-        uint32_t band_mask, uint32_t iface_mode_mask);
+        uint32_t band_mask, uint32_t iface_mode_mask, uint32_t filter_mask);
 
    private:
     // Retrieve interface handles for all the available interfaces.
diff --git a/wifi/1.5/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.5/vts/functional/wifi_chip_hidl_test.cpp
index 509f1bd..5ac747d 100644
--- a/wifi/1.5/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.5/vts/functional/wifi_chip_hidl_test.cpp
@@ -195,10 +195,12 @@
 TEST_P(WifiChipHidlTest, getUsableChannels) {
     uint32_t ifaceModeMask =
         WifiIfaceMode::IFACE_MODE_P2P_CLIENT | WifiIfaceMode::IFACE_MODE_P2P_GO;
+    uint32_t filterMask = IWifiChip::UsableChannelFilter::CELLULAR_COEXISTENCE |
+                          IWifiChip::UsableChannelFilter::CONCURRENCY;
     configureChipForIfaceType(IfaceType::STA, true);
     WifiBand band = WifiBand::BAND_24GHZ_5GHZ_6GHZ;
-    const auto& statusNonEmpty =
-        HIDL_INVOKE(wifi_chip_, getUsableChannels, band, ifaceModeMask);
+    const auto& statusNonEmpty = HIDL_INVOKE(wifi_chip_, getUsableChannels,
+                                             band, ifaceModeMask, filterMask);
     if (statusNonEmpty.first.code != WifiStatusCode::SUCCESS) {
         EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED,
                   statusNonEmpty.first.code);