Merge "Remove use of size_t in Rust code"
diff --git a/fsverity_init/main.cpp b/fsverity_init/main.cpp
index 3f75dca..b502b91 100644
--- a/fsverity_init/main.cpp
+++ b/fsverity_init/main.cpp
@@ -48,12 +48,6 @@
             return -1;
         }
     } else if (command == "--lock") {
-        // Requires files backed by fs-verity to be verified with a key in .fs-verity
-        // keyring.
-        if (!android::base::WriteStringToFile("1", "/proc/sys/fs/verity/require_signatures")) {
-            PLOG(ERROR) << "Failed to enforce fs-verity signature";
-        }
-
         if (!android::base::GetBoolProperty("ro.debuggable", false)) {
             if (keyctl_restrict_keyring(keyring_id, nullptr, nullptr) < 0) {
                 PLOG(ERROR) << "Cannot restrict .fs-verity keyring";
diff --git a/identity/Android.bp b/identity/Android.bp
index 9117b7f..7b81685 100644
--- a/identity/Android.bp
+++ b/identity/Android.bp
@@ -32,35 +32,39 @@
     ],
 
     srcs: [
-        "main.cpp",
-        "CredentialStore.cpp",
-        "CredentialStoreFactory.cpp",
-        "WritableCredential.cpp",
         "Credential.cpp",
         "CredentialData.cpp",
+        "CredentialStore.cpp",
+        "CredentialStoreFactory.cpp",
+        "RemotelyProvisionedKey.cpp",
         "Session.cpp",
         "Util.cpp",
+        "WritableCredential.cpp",
+        "main.cpp",
     ],
     init_rc: ["credstore.rc"],
     shared_libs: [
+        "android.hardware.identity-support-lib",
+        "android.hardware.keymaster@4.0",
+        "android.security.authorization-ndk",
+	"android.security.remoteprovisioning-cpp",
         "libbase",
         "libbinder",
         "libbinder_ndk",
-        "android.hardware.keymaster@4.0",
         "libcredstore_aidl",
         "libcrypto",
-        "libutils",
         "libhidlbase",
-        "android.hardware.identity-support-lib",
         "libkeymaster4support",
         "libkeystore-attestation-application-id",
-        "android.security.authorization-ndk",
-        "android.security.remoteprovisioning-cpp",
+        "libutils",
         "libutilscallstack",
+        "libvintf",
+	"server_configurable_flags",
     ],
     static_libs: [
         "android.hardware.security.rkp-V3-cpp",
         "android.hardware.keymaster-V3-cpp",
+        "android.security.rkp_aidl-cpp",
         "libcppbor_external",
     ],
 }
diff --git a/identity/Credential.cpp b/identity/Credential.cpp
index c67fe4a..0b1d171 100644
--- a/identity/Credential.cpp
+++ b/identity/Credential.cpp
@@ -554,9 +554,18 @@
         ret.resultNamespaces.push_back(resultNamespaceParcel);
     }
 
-    status = halBinder->finishRetrieval(&ret.mac, &ret.deviceNameSpaces);
-    if (!status.isOk()) {
-        return halStatusToGenericError(status);
+    // API version 5 (feature version 202301) supports both MAC and ECDSA signature.
+    if (halApiVersion_ >= 5) {
+        status = halBinder->finishRetrievalWithSignature(&ret.mac, &ret.deviceNameSpaces,
+                                                         &ret.signature);
+        if (!status.isOk()) {
+            return halStatusToGenericError(status);
+        }
+    } else {
+        status = halBinder->finishRetrieval(&ret.mac, &ret.deviceNameSpaces);
+        if (!status.isOk()) {
+            return halStatusToGenericError(status);
+        }
     }
     ret.staticAuthenticationData = selectedAuthKeyStaticAuthData_;
 
@@ -694,7 +703,8 @@
     return Status::ok();
 }
 
-Status Credential::setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) {
+Status Credential::setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey,
+                                                  int64_t minValidTimeMillis) {
     if (halSessionBinder_) {
         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                 "Cannot be used with session");
@@ -706,7 +716,7 @@
         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                 "Error loading data for credential");
     }
-    data->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
+    data->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey, minValidTimeMillis);
     if (!data->saveToDisk()) {
         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                 "Error saving data");
@@ -777,11 +787,6 @@
 Credential::storeStaticAuthenticationDataWithExpiration(const AuthKeyParcel& authenticationKey,
                                                         int64_t expirationDateMillisSinceEpoch,
                                                         const vector<uint8_t>& staticAuthData) {
-    if (halApiVersion_ < 3) {
-        return Status::fromServiceSpecificError(ICredentialStore::ERROR_NOT_SUPPORTED,
-                                                "Not implemented by HAL");
-    }
-
     if (halSessionBinder_) {
         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                 "Cannot be used with session");
@@ -828,6 +833,29 @@
     return Status::ok();
 }
 
+Status Credential::getAuthenticationDataExpirations(vector<int64_t>* _aidl_return) {
+    if (halSessionBinder_) {
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+                                                "Cannot be used with session");
+    }
+
+    sp<CredentialData> data = new CredentialData(dataPath_, callingUid_, credentialName_);
+    if (!data->loadFromDisk()) {
+        LOG(ERROR) << "Error loading data for credential";
+        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+                                                "Error loading data for credential");
+    }
+    const vector<AuthKeyData>& authKeyDatas = data->getAuthKeyDatas();
+    vector<int64_t> ret;
+    ret.reserve(authKeyDatas.size());
+    for (const AuthKeyData& authKeyData : authKeyDatas) {
+        // Note: value is INT64_MAX if expiration date is not set.
+        ret.push_back(authKeyData.expirationDateMillisSinceEpoch);
+    }
+    *_aidl_return = ret;
+    return Status::ok();
+}
+
 optional<string> extractDocType(const vector<uint8_t>& credentialData) {
     auto [item, _ /* newPos */, message] = cppbor::parse(credentialData);
     if (item == nullptr) {
@@ -887,8 +915,8 @@
         dataPath_, credentialName_, docType.value(), true, hwInfo_, halWritableCredential);
 
     writableCredential->setAttestationCertificate(data->getAttestationCertificate());
-    auto [keyCount, maxUsesPerKey] = data->getAvailableAuthenticationKeys();
-    writableCredential->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
+    auto [keyCount, maxUsesPerKey, minValidTimeMillis] = data->getAvailableAuthenticationKeys();
+    writableCredential->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey, minValidTimeMillis);
 
     // Because its data has changed, we need to replace the binder for the
     // IIdentityCredential when the credential has been updated... otherwise the
diff --git a/identity/Credential.h b/identity/Credential.h
index 0906fea..4ecf92e 100644
--- a/identity/Credential.h
+++ b/identity/Credential.h
@@ -78,7 +78,8 @@
                       bool allowUsingExpiredKeys, bool incrementUsageCount,
                       GetEntriesResultParcel* _aidl_return) override;
 
-    Status setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) override;
+    Status setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey,
+                                          int64_t minValidTimeMillis) override;
     Status getAuthKeysNeedingCertification(vector<AuthKeyParcel>* _aidl_return) override;
     Status storeStaticAuthenticationData(const AuthKeyParcel& authenticationKey,
                                          const vector<uint8_t>& staticAuthData) override;
@@ -87,6 +88,7 @@
                                                 int64_t expirationDateMillisSinceEpoch,
                                                 const vector<uint8_t>& staticAuthData) override;
     Status getAuthenticationDataUsageCount(vector<int32_t>* _aidl_return) override;
+    Status getAuthenticationDataExpirations(vector<int64_t>* _aidl_return) override;
 
     Status update(sp<IWritableCredential>* _aidl_return) override;
 
diff --git a/identity/CredentialData.cpp b/identity/CredentialData.cpp
index 2189f90..fb08333 100644
--- a/identity/CredentialData.cpp
+++ b/identity/CredentialData.cpp
@@ -117,6 +117,7 @@
     map.add("entryData", std::move(encryptedBlobsMap));
     map.add("authKeyCount", keyCount_);
     map.add("maxUsesPerAuthKey", maxUsesPerKey_);
+    map.add("minValidTimeMillis", minValidTimeMillis_);
 
     cppbor::Array authKeyDatasArray;
     for (const AuthKeyData& data : authKeyDatas_) {
@@ -253,6 +254,7 @@
     authKeyDatas_.clear();
     keyCount_ = 0;
     maxUsesPerKey_ = 1;
+    minValidTimeMillis_ = 0;
 
     optional<vector<uint8_t>> data = fileGetContents(fileName_);
     if (!data) {
@@ -398,6 +400,14 @@
                 return false;
             }
             maxUsesPerKey_ = number->value();
+
+        } else if (key == "minValidTimeMillis") {
+            const cppbor::Int* number = valueItem->asInt();
+            if (number == nullptr) {
+                LOG(ERROR) << "Value for minValidTimeMillis is not a number";
+                return false;
+            }
+            minValidTimeMillis_ = number->value();
         }
     }
 
@@ -479,9 +489,11 @@
 
 // ---
 
-void CredentialData::setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey) {
+void CredentialData::setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey,
+                                                    int64_t minValidTimeMillis) {
     keyCount_ = keyCount;
     maxUsesPerKey_ = maxUsesPerKey;
+    minValidTimeMillis_ = minValidTimeMillis;
 
     // If growing the number of auth keys (prevKeyCount < keyCount_ case) we'll add
     // new AuthKeyData structs to |authKeyDatas_| and each struct will have empty |certificate|
@@ -499,8 +511,9 @@
     return authKeyDatas_;
 }
 
-pair<int /* keyCount */, int /*maxUsersPerKey */> CredentialData::getAvailableAuthenticationKeys() {
-    return std::make_pair(keyCount_, maxUsesPerKey_);
+tuple<int /* keyCount */, int /*maxUsersPerKey */, int64_t /* minValidTimeMillis */>
+CredentialData::getAvailableAuthenticationKeys() const {
+    return std::make_tuple(keyCount_, maxUsesPerKey_, minValidTimeMillis_);
 }
 
 AuthKeyData* CredentialData::findAuthKey_(bool allowUsingExhaustedKeys,
@@ -573,9 +586,10 @@
 
     for (AuthKeyData& data : authKeyDatas_) {
         bool keyExceedUseCount = (data.useCount >= maxUsesPerKey_);
-        bool keyBeyondExpirationDate = (nowMilliSeconds > data.expirationDateMillisSinceEpoch);
+        int64_t expirationDateAdjusted = data.expirationDateMillisSinceEpoch - minValidTimeMillis_;
+        bool keyBeyondAdjustedExpirationDate = (nowMilliSeconds > expirationDateAdjusted);
         bool newKeyNeeded =
-            (data.certificate.size() == 0) || keyExceedUseCount || keyBeyondExpirationDate;
+            (data.certificate.size() == 0) || keyExceedUseCount || keyBeyondAdjustedExpirationDate;
         bool certificationPending = (data.pendingCertificate.size() > 0);
         if (newKeyNeeded && !certificationPending) {
             vector<uint8_t> signingKeyBlob;
diff --git a/identity/CredentialData.h b/identity/CredentialData.h
index e240e47..3f7cd3a 100644
--- a/identity/CredentialData.h
+++ b/identity/CredentialData.h
@@ -37,7 +37,6 @@
 using ::android::hardware::identity::SecureAccessControlProfile;
 using ::std::map;
 using ::std::optional;
-using ::std::pair;
 using ::std::string;
 using ::std::tuple;
 using ::std::vector;
@@ -89,7 +88,8 @@
 
     bool deleteCredential();
 
-    void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey);
+    void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey,
+                                        int64_t minValidTimeMillis);
 
     // Getters
 
@@ -107,7 +107,8 @@
 
     const vector<AuthKeyData>& getAuthKeyDatas() const;
 
-    pair<int /* keyCount */, int /*maxUsersPerKey */> getAvailableAuthenticationKeys();
+    tuple<int /* keyCount */, int /*maxUsersPerKey */, int64_t /* minValidTimeMillis */>
+    getAvailableAuthenticationKeys() const;
 
     // Returns |nullptr| if a suitable key cannot be found. Otherwise returns
     // the authentication and increases its use-count.
@@ -143,6 +144,7 @@
 
     int keyCount_ = 0;
     int maxUsesPerKey_ = 1;
+    int64_t minValidTimeMillis_ = 0;
     vector<AuthKeyData> authKeyDatas_;  // Always |keyCount_| long.
 };
 
diff --git a/identity/CredentialStore.cpp b/identity/CredentialStore.cpp
index c5c429b..eb9bdb6 100644
--- a/identity/CredentialStore.cpp
+++ b/identity/CredentialStore.cpp
@@ -26,6 +26,8 @@
 #include <android/security/remoteprovisioning/RemotelyProvisionedKey.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
+#include <server_configurable_flags/get_flags.h>
+#include <vintf/VintfObject.h>
 
 #include "Credential.h"
 #include "CredentialData.h"
@@ -39,41 +41,14 @@
 namespace identity {
 namespace {
 
-using ::android::hardware::security::keymint::IRemotelyProvisionedComponent;
-using ::android::hardware::security::keymint::RpcHardwareInfo;
 using ::android::security::remoteprovisioning::IRemotelyProvisionedKeyPool;
-using ::android::security::remoteprovisioning::RemotelyProvisionedKey;
+using ::android::security::rkp::IRemoteProvisioning;
 
-std::optional<std::string>
-getRemotelyProvisionedComponentId(const sp<IIdentityCredentialStore>& hal) {
-    auto init = [](const sp<IIdentityCredentialStore>& hal) -> std::optional<std::string> {
-        sp<IRemotelyProvisionedComponent> remotelyProvisionedComponent;
-        Status status = hal->getRemotelyProvisionedComponent(&remotelyProvisionedComponent);
-        if (!status.isOk()) {
-            LOG(ERROR) << "Error getting remotely provisioned component: " << status;
-            return std::nullopt;
-        }
-
-        RpcHardwareInfo rpcHwInfo;
-        status = remotelyProvisionedComponent->getHardwareInfo(&rpcHwInfo);
-        if (!status.isOk()) {
-            LOG(ERROR) << "Error getting remotely provisioned component hardware info: " << status;
-            return std::nullopt;
-        }
-
-        if (!rpcHwInfo.uniqueId) {
-            LOG(ERROR) << "Remotely provisioned component is missing a unique id, which is "
-                       << "required for credential key remotely provisioned attestation keys. "
-                       << "This is a bug in the vendor implementation.";
-            return std::nullopt;
-        }
-
-        // This id is required to later fetch remotely provisioned attestation keys.
-        return *rpcHwInfo.uniqueId;
-    };
-
-    static std::optional<std::string> id = init(hal);
-    return id;
+bool useRkpd() {
+    std::string useRkpdFlagValue = server_configurable_flags::GetServerConfigurableFlag(
+        "remote_key_provisioning_native", "enable_rkpd",
+        /*default_value=*/"false");
+    return useRkpdFlagValue == "true";
 }
 
 }  // namespace
@@ -90,13 +65,30 @@
     halApiVersion_ = hal_->getInterfaceVersion();
 
     if (hwInfo_.isRemoteKeyProvisioningSupported) {
-        keyPool_ = android::waitForService<IRemotelyProvisionedKeyPool>(
-            IRemotelyProvisionedKeyPool::descriptor);
-        if (keyPool_.get() == nullptr) {
-            LOG(ERROR) << "Error getting IRemotelyProvisionedKeyPool HAL with service name '"
-                       << IRemotelyProvisionedKeyPool::descriptor << "'";
+        status = hal_->getRemotelyProvisionedComponent(&rpc_);
+        if (!status.isOk()) {
+            LOG(ERROR) << "Error getting remotely provisioned component: " << status;
             return false;
         }
+        useRkpd_ = useRkpd();
+
+        if (useRkpd_) {
+            uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
+            auto rpcKeyFuture = getRpcKeyFuture(rpc_, callingUid);
+            if (!rpcKeyFuture) {
+                LOG(ERROR) << "Error in getRpcKeyFuture()";
+                return false;
+            }
+            rpcKeyFuture_ = std::move(*rpcKeyFuture);
+        } else {
+            keyPool_ = android::waitForService<IRemotelyProvisionedKeyPool>(
+                IRemotelyProvisionedKeyPool::descriptor);
+            if (!keyPool_) {
+                LOG(ERROR) << "Error getting IRemotelyProvisionedKeyPool HAL with service name '"
+                           << IRemotelyProvisionedKeyPool::descriptor << "'";
+                return false;
+            }
+        }
     }
 
     LOG(INFO) << "Connected to Identity Credential HAL with API version " << halApiVersion_
@@ -209,28 +201,54 @@
 
 Status CredentialStore::setRemotelyProvisionedAttestationKey(
     IWritableIdentityCredential* halWritableCredential) {
-    std::optional<std::string> rpcId = getRemotelyProvisionedComponentId(hal_);
-    if (!rpcId) {
-        return Status::fromServiceSpecificError(ERROR_GENERIC,
-                                                "Error getting remotely provisioned component id");
+    std::vector<uint8_t> keyBlob;
+    std::vector<uint8_t> encodedCertChain;
+    Status status;
+
+    if (useRkpd_) {
+        if (rpcKeyFuture_.wait_for(std::chrono::seconds(10)) != std::future_status::ready) {
+            return Status::fromServiceSpecificError(
+                ERROR_GENERIC, "Waiting for remotely provisioned attestation key timed out");
+        }
+
+        std::optional<::android::security::rkp::RemotelyProvisionedKey> key = rpcKeyFuture_.get();
+        if (!key) {
+            return Status::fromServiceSpecificError(
+                ERROR_GENERIC, "Failed to get remotely provisioned attestation key");
+        }
+
+        if (key->keyBlob.empty()) {
+            return Status::fromServiceSpecificError(
+                ERROR_GENERIC, "Remotely provisioned attestation key blob is empty");
+        }
+
+        keyBlob = std::move(key->keyBlob);
+        encodedCertChain = std::move(key->encodedCertChain);
+    } else {
+        std::optional<std::string> rpcId = getRpcId(rpc_);
+        if (!rpcId) {
+            return Status::fromServiceSpecificError(
+                ERROR_GENERIC, "Error getting remotely provisioned component id");
+        }
+
+        uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
+        ::android::security::remoteprovisioning::RemotelyProvisionedKey key;
+        Status status = keyPool_->getAttestationKey(callingUid, *rpcId, &key);
+        if (!status.isOk()) {
+            LOG(WARNING) << "Unable to fetch remotely provisioned attestation key, falling back "
+                         << "to the factory-provisioned attestation key.";
+            return Status::ok();
+        }
+
+        keyBlob = std::move(key.keyBlob);
+        encodedCertChain = std::move(key.encodedCertChain);
     }
 
-    uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
-    RemotelyProvisionedKey key;
-    Status status = keyPool_->getAttestationKey(callingUid, *rpcId, &key);
-    if (!status.isOk()) {
-        LOG(WARNING) << "Unable to fetch remotely provisioned attestation key, falling back "
-                     << "to the factory-provisioned attestation key.";
-        return Status::ok();
-    }
-
-    status = halWritableCredential->setRemotelyProvisionedAttestationKey(key.keyBlob,
-                                                                         key.encodedCertChain);
+    status = halWritableCredential->setRemotelyProvisionedAttestationKey(keyBlob, encodedCertChain);
     if (!status.isOk()) {
         LOG(ERROR) << "Error setting remotely provisioned attestation key on credential";
         return status;
     }
-
     return Status::ok();
 }
 
diff --git a/identity/CredentialStore.h b/identity/CredentialStore.h
index df7928e..495841b 100644
--- a/identity/CredentialStore.h
+++ b/identity/CredentialStore.h
@@ -17,12 +17,16 @@
 #ifndef SYSTEM_SECURITY_CREDENTIAL_STORE_H_
 #define SYSTEM_SECURITY_CREDENTIAL_STORE_H_
 
+#include <future>
 #include <string>
 #include <vector>
 
 #include <android/hardware/identity/IIdentityCredentialStore.h>
 #include <android/security/identity/BnCredentialStore.h>
 #include <android/security/remoteprovisioning/IRemotelyProvisionedKeyPool.h>
+#include <android/security/rkp/IRemoteProvisioning.h>
+
+#include "RemotelyProvisionedKey.h"
 
 namespace android {
 namespace security {
@@ -39,6 +43,7 @@
 using ::android::hardware::identity::IIdentityCredentialStore;
 using ::android::hardware::identity::IPresentationSession;
 using ::android::hardware::identity::IWritableIdentityCredential;
+using ::android::hardware::security::keymint::IRemotelyProvisionedComponent;
 using ::android::security::remoteprovisioning::IRemotelyProvisionedKeyPool;
 
 class CredentialStore : public BnCredentialStore {
@@ -73,9 +78,12 @@
     sp<IIdentityCredentialStore> hal_;
     int halApiVersion_;
 
-    sp<IRemotelyProvisionedKeyPool> keyPool_;
-
     HardwareInformation hwInfo_;
+
+    bool useRkpd_;
+    sp<IRemotelyProvisionedComponent> rpc_;
+    sp<IRemotelyProvisionedKeyPool> keyPool_;
+    std::future<std::optional<RemotelyProvisionedKey>> rpcKeyFuture_;
 };
 
 }  // namespace identity
diff --git a/identity/RemotelyProvisionedKey.cpp b/identity/RemotelyProvisionedKey.cpp
new file mode 100644
index 0000000..46a42f4
--- /dev/null
+++ b/identity/RemotelyProvisionedKey.cpp
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "credstore"
+
+#include <atomic>
+
+#include <android-base/logging.h>
+#include <android/security/rkp/BnGetKeyCallback.h>
+#include <android/security/rkp/BnGetRegistrationCallback.h>
+#include <android/security/rkp/IRemoteProvisioning.h>
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+#include <vintf/VintfObject.h>
+
+#include "RemotelyProvisionedKey.h"
+
+namespace android {
+namespace security {
+namespace identity {
+namespace {
+
+using ::android::binder::Status;
+using ::android::hardware::security::keymint::IRemotelyProvisionedComponent;
+using ::android::hardware::security::keymint::RpcHardwareInfo;
+using ::android::security::rkp::BnGetKeyCallback;
+using ::android::security::rkp::BnGetRegistrationCallback;
+using ::android::security::rkp::IRegistration;
+using ::android::security::rkp::IRemoteProvisioning;
+using ::android::security::rkp::RemotelyProvisionedKey;
+
+std::optional<String16> findRpcNameById(std::string_view targetRpcId) {
+    auto deviceManifest = vintf::VintfObject::GetDeviceHalManifest();
+    auto instances = deviceManifest->getAidlInstances("android.hardware.security.keymint",
+                                                      "IRemotelyProvisionedComponent");
+    for (const std::string& instance : instances) {
+        auto rpcName =
+            IRemotelyProvisionedComponent::descriptor + String16("/") + String16(instance.c_str());
+        sp<IRemotelyProvisionedComponent> rpc =
+            android::waitForService<IRemotelyProvisionedComponent>(rpcName);
+
+        auto rpcId = getRpcId(rpc);
+        if (!rpcId) {
+            continue;
+        }
+        if (*rpcId == targetRpcId) {
+            return rpcName;
+        }
+    }
+
+    LOG(ERROR) << "Remotely provisioned component with given unique ID: " << targetRpcId
+               << " not found";
+    return std::nullopt;
+}
+
+std::optional<String16> getRpcName(const sp<IRemotelyProvisionedComponent>& rpc) {
+    std::optional<std::string> targetRpcId = getRpcId(rpc);
+    if (!targetRpcId) {
+        return std::nullopt;
+    }
+    return findRpcNameById(*targetRpcId);
+}
+
+class GetKeyCallback : public BnGetKeyCallback {
+  public:
+    GetKeyCallback(std::promise<std::optional<RemotelyProvisionedKey>> keyPromise)
+        : keyPromise_(std::move(keyPromise)), called_() {}
+
+    Status onSuccess(const RemotelyProvisionedKey& key) override {
+        if (called_.test_and_set()) {
+            return Status::ok();
+        }
+        keyPromise_.set_value(key);
+        return Status::ok();
+    }
+    Status onCancel() override {
+        if (called_.test_and_set()) {
+            return Status::ok();
+        }
+        LOG(ERROR) << "GetKeyCallback cancelled";
+        keyPromise_.set_value(std::nullopt);
+        return Status::ok();
+    }
+    Status onError(const String16& error) override {
+        if (called_.test_and_set()) {
+            return Status::ok();
+        }
+        LOG(ERROR) << "GetKeyCallback failed: " << error;
+        keyPromise_.set_value(std::nullopt);
+        return Status::ok();
+    }
+
+  private:
+    std::promise<std::optional<RemotelyProvisionedKey>> keyPromise_;
+    // This callback can only be called into once
+    std::atomic_flag called_;
+};
+
+class GetRegistrationCallback : public BnGetRegistrationCallback {
+  public:
+    GetRegistrationCallback(std::promise<std::optional<RemotelyProvisionedKey>> keyPromise,
+                            uint32_t keyId)
+        : keyPromise_(std::move(keyPromise)), keyId_(keyId), called_() {}
+
+    Status onSuccess(const sp<IRegistration>& registration) override {
+        if (called_.test_and_set()) {
+            return Status::ok();
+        }
+        auto cb = sp<GetKeyCallback>::make(std::move(keyPromise_));
+        auto status = registration->getKey(keyId_, cb);
+        if (!status.isOk()) {
+            cb->onError(String16("Failed to register GetKeyCallback"));
+        }
+        return Status::ok();
+    }
+    Status onCancel() override {
+        if (called_.test_and_set()) {
+            return Status::ok();
+        }
+        LOG(ERROR) << "GetRegistrationCallback cancelled";
+        keyPromise_.set_value(std::nullopt);
+        return Status::ok();
+    }
+    Status onError(const String16& error) override {
+        if (called_.test_and_set()) {
+            return Status::ok();
+        }
+        LOG(ERROR) << "GetRegistrationCallback failed: " << error;
+        keyPromise_.set_value(std::nullopt);
+        return Status::ok();
+    }
+
+  private:
+    std::promise<std::optional<RemotelyProvisionedKey>> keyPromise_;
+    int32_t keyId_;
+    // This callback can only be called into once
+    std::atomic_flag called_;
+};
+
+}  // namespace
+
+std::optional<std::string> getRpcId(const sp<IRemotelyProvisionedComponent>& rpc) {
+    RpcHardwareInfo rpcHwInfo;
+    Status status = rpc->getHardwareInfo(&rpcHwInfo);
+    if (!status.isOk()) {
+        LOG(ERROR) << "Error getting remotely provisioned component hardware info: " << status;
+        return std::nullopt;
+    }
+
+    if (!rpcHwInfo.uniqueId) {
+        LOG(ERROR) << "Remotely provisioned component is missing a unique id, which is "
+                   << "required for credential key remotely provisioned attestation keys. "
+                   << "This is a bug in the vendor implementation.";
+        return std::nullopt;
+    }
+
+    return *rpcHwInfo.uniqueId;
+}
+
+std::optional<std::future<std::optional<RemotelyProvisionedKey>>>
+getRpcKeyFuture(const sp<IRemotelyProvisionedComponent>& rpc, int32_t keyId) {
+    std::promise<std::optional<RemotelyProvisionedKey>> keyPromise;
+    auto keyFuture = keyPromise.get_future();
+
+    auto rpcName = getRpcName(rpc);
+    if (!rpcName) {
+        LOG(ERROR) << "Failed to get IRemotelyProvisionedComponent name";
+        return std::nullopt;
+    }
+
+    sp<IRemoteProvisioning> remoteProvisioning =
+        android::waitForService<IRemoteProvisioning>(IRemoteProvisioning::descriptor);
+    if (!remoteProvisioning) {
+        LOG(ERROR) << "Failed to get IRemoteProvisioning HAL";
+        return std::nullopt;
+    }
+
+    auto cb = sp<GetRegistrationCallback>::make(std::move(keyPromise), keyId);
+    Status status = remoteProvisioning->getRegistration(*rpcName, cb);
+    if (!status.isOk()) {
+        LOG(ERROR) << "Failed getRegistration()";
+        return std::nullopt;
+    }
+
+    return keyFuture;
+}
+
+}  // namespace identity
+}  // namespace security
+}  // namespace android
diff --git a/identity/RemotelyProvisionedKey.h b/identity/RemotelyProvisionedKey.h
new file mode 100644
index 0000000..e7ddfca
--- /dev/null
+++ b/identity/RemotelyProvisionedKey.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <future>
+#include <optional>
+
+#include <android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
+
+namespace android {
+namespace security {
+namespace identity {
+
+using ::android::hardware::security::keymint::IRemotelyProvisionedComponent;
+using ::android::security::rkp::RemotelyProvisionedKey;
+
+std::optional<std::string> getRpcId(const sp<IRemotelyProvisionedComponent>& rpc);
+
+std::optional<std::future<std::optional<RemotelyProvisionedKey>>>
+getRpcKeyFuture(const sp<IRemotelyProvisionedComponent>& rpc, int32_t keyId);
+
+}  // namespace identity
+}  // namespace security
+}  // namespace android
diff --git a/identity/WritableCredential.cpp b/identity/WritableCredential.cpp
index 9827d75..d863494 100644
--- a/identity/WritableCredential.cpp
+++ b/identity/WritableCredential.cpp
@@ -101,9 +101,11 @@
     attestationCertificate_ = attestationCertificate;
 }
 
-void WritableCredential::setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey) {
+void WritableCredential::setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey,
+                                                        int64_t minValidTimeMillis) {
     keyCount_ = keyCount;
     maxUsesPerKey_ = maxUsesPerKey;
+    minValidTimeMillis_ = minValidTimeMillis;
 }
 
 ssize_t WritableCredential::calcExpectedProofOfProvisioningSize(
@@ -260,7 +262,7 @@
     }
     data.setCredentialData(credentialData);
 
-    data.setAvailableAuthenticationKeys(keyCount_, maxUsesPerKey_);
+    data.setAvailableAuthenticationKeys(keyCount_, maxUsesPerKey_, minValidTimeMillis_);
 
     if (!data.saveToDisk()) {
         return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
diff --git a/identity/WritableCredential.h b/identity/WritableCredential.h
index 838b956..c92d58a 100644
--- a/identity/WritableCredential.h
+++ b/identity/WritableCredential.h
@@ -45,7 +45,8 @@
 
     // Used when updating a credential
     void setAttestationCertificate(const vector<uint8_t>& attestationCertificate);
-    void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey);
+    void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey,
+                                        int64_t minValidTimeMillis);
 
     // Used by Credential::update()
     void setCredentialToReloadWhenUpdated(sp<Credential> credential);
@@ -69,6 +70,7 @@
     vector<uint8_t> attestationCertificate_;
     int keyCount_ = 0;
     int maxUsesPerKey_ = 1;
+    int64_t minValidTimeMillis_ = 0;
 
     sp<Credential> credentialToReloadWhenUpdated_;
 
diff --git a/identity/binder/android/security/identity/GetEntriesResultParcel.aidl b/identity/binder/android/security/identity/GetEntriesResultParcel.aidl
index 03b363c..51281b9 100644
--- a/identity/binder/android/security/identity/GetEntriesResultParcel.aidl
+++ b/identity/binder/android/security/identity/GetEntriesResultParcel.aidl
@@ -26,4 +26,5 @@
     byte[] deviceNameSpaces;
     byte[] mac;
     byte[] staticAuthenticationData;
+    byte[] signature;                      // Added in Android 14 / U
 }
diff --git a/identity/binder/android/security/identity/ICredential.aidl b/identity/binder/android/security/identity/ICredential.aidl
index e6a9fae..875b934 100644
--- a/identity/binder/android/security/identity/ICredential.aidl
+++ b/identity/binder/android/security/identity/ICredential.aidl
@@ -60,7 +60,9 @@
                                       in boolean allowUsingExpiredKeys,
                                       in boolean incrementUsageCount);
 
-    void setAvailableAuthenticationKeys(in int keyCount, in int maxUsesPerKey);
+    void setAvailableAuthenticationKeys(in int keyCount,
+                                        in int maxUsesPerKey,
+                                        in long minValidTimeMillis);
 
     AuthKeyParcel[] getAuthKeysNeedingCertification();
 
@@ -73,6 +75,8 @@
 
     int[] getAuthenticationDataUsageCount();
 
+    long[] getAuthenticationDataExpirations();
+
     IWritableCredential update();
 }
 
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index 51ce9d1..fa80563 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -41,8 +41,10 @@
         "android.security.maintenance-rust",
         "android.security.metrics-rust",
         "android.security.remoteprovisioning-rust",
+        "android.security.rkp_aidl-rust",
         "libanyhow",
         "libbinder_rs",
+        "libfutures",
         "libkeystore2_aaid-rust",
         "libkeystore2_apc_compat-rust",
         "libkeystore2_crypto_rust",
diff --git a/keystore2/aidl/Android.bp b/keystore2/aidl/Android.bp
index 1e6d4dc..e3961da 100644
--- a/keystore2/aidl/Android.bp
+++ b/keystore2/aidl/Android.bp
@@ -128,7 +128,7 @@
     name: "android.security.maintenance",
     srcs: [ "android/security/maintenance/*.aidl" ],
     imports: [
-        "android.system.keystore2-V2",
+        "android.system.keystore2-V3",
     ],
     unstable: true,
     backend: {
@@ -167,7 +167,7 @@
     name: "android.security.metrics",
     srcs: [ "android/security/metrics/*.aidl" ],
     imports: [
-        "android.system.keystore2-V2",
+        "android.system.keystore2-V3",
     ],
     unstable: true,
     backend: {
@@ -184,29 +184,68 @@
     },
 }
 
+// java_defaults that includes the latest Keystore2 AIDL library.
+// Modules that depend on KeyMint directly can include this java_defaults to avoid
+// managing dependency versions explicitly.
+java_defaults {
+    name: "keystore2_use_latest_aidl_java_static",
+    static_libs: [
+        "android.system.keystore2-V3-java-source"
+    ],
+}
+
+java_defaults {
+    name: "keystore2_use_latest_aidl_java_shared",
+    libs: [
+        "android.system.keystore2-V3-java-source"
+    ],
+}
+
+java_defaults {
+    name: "keystore2_use_latest_aidl_java",
+    libs: [
+        "android.system.keystore2-V3-java"
+    ],
+}
+
 // cc_defaults that includes the latest Keystore2 AIDL library.
 // Modules that depend on KeyMint directly can include this cc_defaults to avoid
 // managing dependency versions explicitly.
 cc_defaults {
     name: "keystore2_use_latest_aidl_ndk_static",
     static_libs: [
-        "android.system.keystore2-V2-ndk",
+        "android.system.keystore2-V3-ndk",
     ],
 }
 
 cc_defaults {
     name: "keystore2_use_latest_aidl_ndk_shared",
     shared_libs: [
-        "android.system.keystore2-V2-ndk",
+        "android.system.keystore2-V3-ndk",
     ],
 }
 
+cc_defaults {
+    name: "keystore2_use_latest_aidl_cpp_shared",
+    shared_libs: [
+        "android.system.keystore2-V3-cpp",
+    ],
+}
+
+cc_defaults {
+    name: "keystore2_use_latest_aidl_cpp_static",
+    static_libs: [
+        "android.system.keystore2-V3-cpp",
+    ],
+}
+
+
 // A rust_defaults that includes the latest Keystore2 AIDL library.
 // Modules that depend on Keystore2 directly can include this rust_defaults to avoid
 // managing dependency versions explicitly.
 rust_defaults {
     name: "keystore2_use_latest_aidl_rust",
     rustlibs: [
-        "android.system.keystore2-V2-rust",
+        "android.system.keystore2-V3-rust",
     ],
 }
diff --git a/keystore2/android.system.keystore2-service.xml b/keystore2/android.system.keystore2-service.xml
index 20c2fba..45f995c 100644
--- a/keystore2/android.system.keystore2-service.xml
+++ b/keystore2/android.system.keystore2-service.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="framework">
     <hal format="aidl">
         <name>android.system.keystore2</name>
-        <version>2</version>
+        <version>3</version>
         <interface>
             <name>IKeystoreService</name>
             <instance>default</instance>
diff --git a/keystore2/src/attestation_key_utils.rs b/keystore2/src/attestation_key_utils.rs
index 94f3e4c..d01cf86 100644
--- a/keystore2/src/attestation_key_utils.rs
+++ b/keystore2/src/attestation_key_utils.rs
@@ -40,6 +40,10 @@
         attestation_key: AttestationKey,
         attestation_certs: Certificate,
     },
+    RkpdProvisioned {
+        attestation_key: AttestationKey,
+        attestation_certs: Certificate,
+    },
     UserGenerated {
         key_id_guard: KeyIdGuard,
         blob: Vec<u8>,
@@ -48,6 +52,12 @@
     },
 }
 
+fn use_rkpd() -> bool {
+    let property_name = "persist.device_config.remote_key_provisioning_native.enable_rkpd";
+    let default_value = false;
+    rustutils::system_properties::read_bool(property_name, default_value).unwrap_or(default_value)
+}
+
 /// This function loads and, optionally, assigns the caller's remote provisioned
 /// attestation key if a challenge is present. Alternatively, if `attest_key_descriptor` is given,
 /// it loads the user generated attestation key from the database.
@@ -64,18 +74,34 @@
         params.iter().any(|kp| kp.tag == Tag::DEVICE_UNIQUE_ATTESTATION);
     match attest_key_descriptor {
         // Do not select an RKP key if DEVICE_UNIQUE_ATTESTATION is present.
-        None if challenge_present && !is_device_unique_attestation => rem_prov_state
-            .get_remotely_provisioned_attestation_key_and_certs(key, caller_uid, params, db)
-            .context(ks_err!("Trying to get remotely provisioned attestation key."))
-            .map(|result| {
-                result.map(|(key_id_guard, attestation_key, attestation_certs)| {
-                    AttestationKeyInfo::RemoteProvisioned {
-                        key_id_guard,
-                        attestation_key,
-                        attestation_certs,
-                    }
-                })
-            }),
+        None if challenge_present && !is_device_unique_attestation => {
+            if use_rkpd() {
+                rem_prov_state
+                    .get_rkpd_attestation_key_and_certs(key, caller_uid, params)
+                    .context(ks_err!("Trying to get attestation key from RKPD."))
+                    .map(|result| {
+                        result.map(|(attestation_key, attestation_certs)| {
+                            AttestationKeyInfo::RkpdProvisioned {
+                                attestation_key,
+                                attestation_certs,
+                            }
+                        })
+                    })
+            } else {
+                rem_prov_state
+                    .get_remotely_provisioned_attestation_key_and_certs(key, caller_uid, params, db)
+                    .context(ks_err!("Trying to get remotely provisioned attestation key."))
+                    .map(|result| {
+                        result.map(|(key_id_guard, attestation_key, attestation_certs)| {
+                            AttestationKeyInfo::RemoteProvisioned {
+                                key_id_guard,
+                                attestation_key,
+                                attestation_certs,
+                            }
+                        })
+                    })
+            }
+        }
         None => Ok(None),
         Some(attest_key) => get_user_generated_attestation_key(attest_key, caller_uid, db)
             .context(ks_err!("Trying to load attest key"))
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index dbdb4e6..62fd579 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -5335,6 +5335,10 @@
                 SecurityLevel::TRUSTED_ENVIRONMENT,
             ),
             KeyParameter::new(
+                KeyParameterValue::AttestationIdSecondIMEI(vec![4u8, 3u8, 1u8, 2u8]),
+                SecurityLevel::TRUSTED_ENVIRONMENT,
+            ),
+            KeyParameter::new(
                 KeyParameterValue::AttestationIdMEID(vec![4u8, 3u8, 1u8, 2u8]),
                 SecurityLevel::TRUSTED_ENVIRONMENT,
             ),
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index 425812f..ed59578 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -441,13 +441,12 @@
 static REMOTE_PROVISIONING_HAL_SERVICE_NAME: &str =
     "android.hardware.security.keymint.IRemotelyProvisionedComponent";
 
-fn connect_remotely_provisioned_component(
-    security_level: &SecurityLevel,
-) -> Result<Strong<dyn IRemotelyProvisionedComponent>> {
+/// Get the service name of a remotely provisioned component corresponding to given security level.
+pub fn get_remotely_provisioned_component_name(security_level: &SecurityLevel) -> Result<String> {
     let remotely_prov_instances =
         get_aidl_instances("android.hardware.security.keymint", 1, "IRemotelyProvisionedComponent");
 
-    let service_name = match *security_level {
+    match *security_level {
         SecurityLevel::TRUSTED_ENVIRONMENT => {
             if remotely_prov_instances.iter().any(|instance| *instance == "default") {
                 Some(format!("{}/default", REMOTE_PROVISIONING_HAL_SERVICE_NAME))
@@ -465,8 +464,13 @@
         _ => None,
     }
     .ok_or(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE))
-    .context(ks_err!())?;
+    .context(ks_err!())
+}
 
+fn connect_remotely_provisioned_component(
+    security_level: &SecurityLevel,
+) -> Result<Strong<dyn IRemotelyProvisionedComponent>> {
+    let service_name = get_remotely_provisioned_component_name(security_level)?;
     let rem_prov_hal: Strong<dyn IRemotelyProvisionedComponent> =
         map_binder_status_code(binder::get_interface(&service_name))
             .context(ks_err!("Trying to connect to RemotelyProvisionedComponent service."))?;
diff --git a/keystore2/src/key_parameter.rs b/keystore2/src/key_parameter.rs
index 9854974..b3dcf45 100644
--- a/keystore2/src/key_parameter.rs
+++ b/keystore2/src/key_parameter.rs
@@ -966,9 +966,12 @@
     /// Provides the device's serial number, to attestKey()
     #[key_param(tag = ATTESTATION_ID_SERIAL, field = Blob)]
     AttestationIdSerial(Vec<u8>),
-    /// Provides the IMEIs for all radios on the device, to attestKey()
+    /// Provides the primary IMEI for the device, to attestKey()
     #[key_param(tag = ATTESTATION_ID_IMEI, field = Blob)]
     AttestationIdIMEI(Vec<u8>),
+    /// Provides a second IMEI for the device, to attestKey()
+    #[key_param(tag = ATTESTATION_ID_SECOND_IMEI, field = Blob)]
+    AttestationIdSecondIMEI(Vec<u8>),
     /// Provides the MEIDs for all radios on the device, to attestKey()
     #[key_param(tag = ATTESTATION_ID_MEID, field = Blob)]
     AttestationIdMEID(Vec<u8>),
diff --git a/keystore2/src/keystore2_main.rs b/keystore2/src/keystore2_main.rs
index c54753c..8c5bf0f 100644
--- a/keystore2/src/keystore2_main.rs
+++ b/keystore2/src/keystore2_main.rs
@@ -148,17 +148,20 @@
 
     // Devices with KS2 and KM 1.0 may not have any IRemotelyProvisionedComponent HALs at all. Do
     // not panic if new_native_binder returns failure because it could not find the TEE HAL.
-    if let Ok(remote_provisioning_service) = RemoteProvisioningService::new_native_binder() {
-        binder::add_service(
-            REMOTE_PROVISIONING_SERVICE_NAME,
-            remote_provisioning_service.as_binder(),
-        )
-        .unwrap_or_else(|e| {
-            panic!(
-                "Failed to register service {} because of {:?}.",
-                REMOTE_PROVISIONING_SERVICE_NAME, e
-            );
-        });
+    match RemoteProvisioningService::new_native_binder() {
+        Ok(remote_provisioning_service) => {
+            binder::add_service(
+                REMOTE_PROVISIONING_SERVICE_NAME,
+                remote_provisioning_service.as_binder(),
+            )
+            .unwrap_or_else(|e| {
+                panic!(
+                    "Failed to register service {} because of {:?}.",
+                    REMOTE_PROVISIONING_SERVICE_NAME, e
+                );
+            });
+        }
+        Err(e) => log::info!("Not publishing {}: {:?}", REMOTE_PROVISIONING_SERVICE_NAME, e),
     }
 
     // Even if the IRemotelyProvisionedComponent HAL is implemented, it doesn't mean that the keys
diff --git a/keystore2/src/km_compat/lib.rs b/keystore2/src/km_compat/lib.rs
index 13f7760..2632ec4 100644
--- a/keystore2/src/km_compat/lib.rs
+++ b/keystore2/src/km_compat/lib.rs
@@ -450,6 +450,10 @@
         )));
         assert!(sec_level_enforced.iter().any(|kp| matches!(
             kp,
+            KeyParameter { tag: Tag::VENDOR_PATCHLEVEL, value: KeyParameterValue::Integer(_) }
+        )));
+        assert!(sec_level_enforced.iter().any(|kp| matches!(
+            kp,
             KeyParameter { tag: Tag::BOOT_PATCHLEVEL, value: KeyParameterValue::Integer(_) }
         )));
     }
diff --git a/keystore2/src/lib.rs b/keystore2/src/lib.rs
index 0b830be..9794889 100644
--- a/keystore2/src/lib.rs
+++ b/keystore2/src/lib.rs
@@ -38,6 +38,7 @@
 pub mod permission;
 pub mod raw_device;
 pub mod remote_provisioning;
+pub mod rkpd_client;
 pub mod security_level;
 pub mod service;
 pub mod shared_secret_negotiation;
diff --git a/keystore2/src/raw_device.rs b/keystore2/src/raw_device.rs
index fe044ee..fa9872a 100644
--- a/keystore2/src/raw_device.rs
+++ b/keystore2/src/raw_device.rs
@@ -63,11 +63,13 @@
     pub const KEY_MINT_V1: i32 = 100;
     /// Version number of KeyMintDevice@V2
     pub const KEY_MINT_V2: i32 = 200;
+    /// Version number of KeyMintDevice@V3
+    pub const KEY_MINT_V3: i32 = 300;
 
     /// Get a [`KeyMintDevice`] for the given [`SecurityLevel`]
     pub fn get(security_level: SecurityLevel) -> Result<KeyMintDevice> {
-        let (km_dev, hw_info, km_uuid) = get_keymint_device(&security_level)
-            .context("In KeyMintDevice::get: get_keymint_device failed")?;
+        let (km_dev, hw_info, km_uuid) =
+            get_keymint_device(&security_level).context(ks_err!("get_keymint_device failed"))?;
 
         Ok(KeyMintDevice {
             km_dev,
@@ -111,12 +113,11 @@
     where
         F: FnOnce(&Strong<dyn IKeyMintDevice>) -> Result<KeyCreationResult, binder::Status>,
     {
-        let creation_result = map_km_error(creator(&self.km_dev))
-            .context("In create_and_store_key: creator failed")?;
+        let creation_result =
+            map_km_error(creator(&self.km_dev)).context(ks_err!("creator failed"))?;
         let key_parameters = key_characteristics_to_internal(creation_result.keyCharacteristics);
 
-        let creation_date =
-            DateTime::now().context("In create_and_store_key: DateTime::now() failed")?;
+        let creation_date = DateTime::now().context(ks_err!("DateTime::now() failed"))?;
 
         let mut key_metadata = KeyMetaData::new();
         key_metadata.add(KeyMetaEntry::CreationDate(creation_date));
@@ -132,7 +133,7 @@
             &key_metadata,
             &self.km_uuid,
         )
-        .context("In create_and_store_key: store_new_key failed")?;
+        .context(ks_err!("store_new_key failed"))?;
         Ok(())
     }
 
@@ -244,7 +245,7 @@
                         .take_key_blob_info()
                         .ok_or(Error::Rc(ResponseCode::KEY_NOT_FOUND))
                         .map(|(key_blob, _)| KeyBlob::NonSensitive(key_blob))
-                        .context("Missing key blob info.")?,
+                        .context(ks_err!("Missing key blob info."))?,
                 ))
             })
             .context(ks_err!("second lookup failed"))
diff --git a/keystore2/src/remote_provisioning.rs b/keystore2/src/remote_provisioning.rs
index fec1b92..cb2962a 100644
--- a/keystore2/src/remote_provisioning.rs
+++ b/keystore2/src/remote_provisioning.rs
@@ -53,6 +53,7 @@
 use crate::ks_err;
 use crate::metrics_store::log_rkp_error_stats;
 use crate::permission::KeystorePerm;
+use crate::rkpd_client::get_rkpd_attestation_key;
 use crate::utils::{check_keystore_permission, watchdog as wd};
 use android_security_metrics::aidl::android::security::metrics::RkpError::RkpError as MetricsRkpError;
 
@@ -184,7 +185,47 @@
             }
         }
     }
+
+    /// Fetches attestation key and corresponding certificates from RKPD.
+    pub fn get_rkpd_attestation_key_and_certs(
+        &self,
+        key: &KeyDescriptor,
+        caller_uid: u32,
+        params: &[KeyParameter],
+    ) -> Result<Option<(AttestationKey, Certificate)>> {
+        if !self.is_asymmetric_key(params) || key.domain != Domain::APP {
+            Ok(None)
+        } else {
+            match get_rkpd_attestation_key(&self.security_level, caller_uid) {
+                Err(e) => {
+                    if self.is_rkp_only() {
+                        log::error!("Error occurred: {:?}", e);
+                        return Err(e);
+                    }
+                    log::warn!("Error occurred: {:?}", e);
+                    log_rkp_error_stats(
+                        MetricsRkpError::FALL_BACK_DURING_HYBRID,
+                        &self.security_level,
+                    );
+                    Ok(None)
+                }
+                Ok(rkpd_key) => Ok(Some((
+                    AttestationKey {
+                        keyBlob: rkpd_key.keyBlob,
+                        attestKeyParams: vec![],
+                        // Batch certificate is at the beginning of the certificate chain.
+                        issuerSubjectName: parse_subject_from_certificate(
+                            &rkpd_key.encodedCertChain,
+                        )
+                        .context(ks_err!("Failed to parse subject."))?,
+                    },
+                    Certificate { encodedCertificate: rkpd_key.encodedCertChain },
+                ))),
+            }
+        }
+    }
 }
+
 /// Implementation of the IRemoteProvisioning service.
 #[derive(Default)]
 pub struct RemoteProvisioningService {
diff --git a/keystore2/src/rkpd_client.rs b/keystore2/src/rkpd_client.rs
new file mode 100644
index 0000000..2d1b23b
--- /dev/null
+++ b/keystore2/src/rkpd_client.rs
@@ -0,0 +1,387 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Helper wrapper around RKPD interface.
+
+use crate::error::{map_binder_status_code, map_or_log_err, Error, ErrorCode};
+use crate::globals::get_remotely_provisioned_component_name;
+use crate::ks_err;
+use crate::utils::watchdog as wd;
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
+use android_security_rkp_aidl::aidl::android::security::rkp::{
+    IGetKeyCallback::BnGetKeyCallback, IGetKeyCallback::IGetKeyCallback,
+    IGetRegistrationCallback::BnGetRegistrationCallback,
+    IGetRegistrationCallback::IGetRegistrationCallback, IRegistration::IRegistration,
+    IRemoteProvisioning::IRemoteProvisioning, RemotelyProvisionedKey::RemotelyProvisionedKey,
+};
+use android_security_rkp_aidl::binder::{BinderFeatures, Interface, Strong};
+use anyhow::{Context, Result};
+use futures::channel::oneshot;
+use futures::executor::block_on;
+use std::sync::Mutex;
+
+type RegistrationSender = oneshot::Sender<Result<binder::Strong<dyn IRegistration>>>;
+
+struct GetRegistrationCallback {
+    registration_tx: Mutex<Option<RegistrationSender>>,
+}
+
+impl GetRegistrationCallback {
+    pub fn new_native_binder(
+        registration_tx: RegistrationSender,
+    ) -> Result<Strong<dyn IGetRegistrationCallback>> {
+        let result: Self =
+            GetRegistrationCallback { registration_tx: Mutex::new(Some(registration_tx)) };
+        Ok(BnGetRegistrationCallback::new_binder(result, BinderFeatures::default()))
+    }
+    fn on_success(&self, registration: &binder::Strong<dyn IRegistration>) -> Result<()> {
+        if let Some(tx) = self.registration_tx.lock().unwrap().take() {
+            tx.send(Ok(registration.clone())).unwrap();
+        }
+        Ok(())
+    }
+    fn on_cancel(&self) -> Result<()> {
+        if let Some(tx) = self.registration_tx.lock().unwrap().take() {
+            tx.send(
+                Err(Error::Km(ErrorCode::OPERATION_CANCELLED))
+                    .context(ks_err!("GetRegistrationCallback cancelled.")),
+            )
+            .unwrap();
+        }
+        Ok(())
+    }
+    fn on_error(&self, error: &str) -> Result<()> {
+        if let Some(tx) = self.registration_tx.lock().unwrap().take() {
+            tx.send(
+                Err(Error::Km(ErrorCode::UNKNOWN_ERROR))
+                    .context(ks_err!("GetRegistrationCallback failed: {:?}", error)),
+            )
+            .unwrap();
+        }
+        Ok(())
+    }
+}
+
+impl Interface for GetRegistrationCallback {}
+
+impl IGetRegistrationCallback for GetRegistrationCallback {
+    fn onSuccess(&self, registration: &Strong<dyn IRegistration>) -> binder::Result<()> {
+        let _wp = wd::watch_millis("IGetRegistrationCallback::onSuccess", 500);
+        map_or_log_err(self.on_success(registration), Ok)
+    }
+    fn onCancel(&self) -> binder::Result<()> {
+        let _wp = wd::watch_millis("IGetRegistrationCallback::onCancel", 500);
+        map_or_log_err(self.on_cancel(), Ok)
+    }
+    fn onError(&self, error: &str) -> binder::Result<()> {
+        let _wp = wd::watch_millis("IGetRegistrationCallback::onError", 500);
+        map_or_log_err(self.on_error(error), Ok)
+    }
+}
+
+/// Make a new connection to a IRegistration service.
+async fn get_rkpd_registration(
+    security_level: &SecurityLevel,
+) -> Result<binder::Strong<dyn IRegistration>> {
+    let remote_provisioning: Strong<dyn IRemoteProvisioning> =
+        map_binder_status_code(binder::get_interface("remote_provisioning"))
+            .context(ks_err!("Trying to connect to IRemoteProvisioning service."))?;
+
+    let rpc_name = get_remotely_provisioned_component_name(security_level)
+        .context(ks_err!("Trying to get IRPC name."))?;
+
+    let (tx, rx) = oneshot::channel();
+    let cb = GetRegistrationCallback::new_native_binder(tx)
+        .context(ks_err!("Trying to create a IGetRegistrationCallback."))?;
+
+    remote_provisioning
+        .getRegistration(&rpc_name, &cb)
+        .context(ks_err!("Trying to get registration."))?;
+
+    rx.await.unwrap()
+}
+
+type KeySender = oneshot::Sender<Result<RemotelyProvisionedKey>>;
+
+struct GetKeyCallback {
+    key_tx: Mutex<Option<KeySender>>,
+}
+
+impl GetKeyCallback {
+    pub fn new_native_binder(key_tx: KeySender) -> Result<Strong<dyn IGetKeyCallback>> {
+        let result: Self = GetKeyCallback { key_tx: Mutex::new(Some(key_tx)) };
+        Ok(BnGetKeyCallback::new_binder(result, BinderFeatures::default()))
+    }
+    fn on_success(&self, key: &RemotelyProvisionedKey) -> Result<()> {
+        if let Some(tx) = self.key_tx.lock().unwrap().take() {
+            tx.send(Ok(RemotelyProvisionedKey {
+                keyBlob: key.keyBlob.clone(),
+                encodedCertChain: key.encodedCertChain.clone(),
+            }))
+            .unwrap();
+        }
+        Ok(())
+    }
+    fn on_cancel(&self) -> Result<()> {
+        if let Some(tx) = self.key_tx.lock().unwrap().take() {
+            tx.send(
+                Err(Error::Km(ErrorCode::OPERATION_CANCELLED))
+                    .context(ks_err!("GetKeyCallback cancelled.")),
+            )
+            .unwrap();
+        }
+        Ok(())
+    }
+    fn on_error(&self, error: &str) -> Result<()> {
+        if let Some(tx) = self.key_tx.lock().unwrap().take() {
+            tx.send(
+                Err(Error::Km(ErrorCode::UNKNOWN_ERROR))
+                    .context(ks_err!("GetKeyCallback failed: {:?}", error)),
+            )
+            .unwrap();
+        }
+        Ok(())
+    }
+}
+
+impl Interface for GetKeyCallback {}
+
+impl IGetKeyCallback for GetKeyCallback {
+    fn onSuccess(&self, key: &RemotelyProvisionedKey) -> binder::Result<()> {
+        let _wp = wd::watch_millis("IGetKeyCallback::onSuccess", 500);
+        map_or_log_err(self.on_success(key), Ok)
+    }
+    fn onCancel(&self) -> binder::Result<()> {
+        let _wp = wd::watch_millis("IGetKeyCallback::onCancel", 500);
+        map_or_log_err(self.on_cancel(), Ok)
+    }
+    fn onError(&self, error: &str) -> binder::Result<()> {
+        let _wp = wd::watch_millis("IGetKeyCallback::onError", 500);
+        map_or_log_err(self.on_error(error), Ok)
+    }
+}
+
+async fn get_rkpd_attestation_key_async(
+    security_level: &SecurityLevel,
+    caller_uid: u32,
+) -> Result<RemotelyProvisionedKey> {
+    let registration = get_rkpd_registration(security_level)
+        .await
+        .context(ks_err!("Trying to get to IRegistration service."))?;
+
+    let (tx, rx) = oneshot::channel();
+    let cb = GetKeyCallback::new_native_binder(tx)
+        .context(ks_err!("Trying to create a IGetKeyCallback."))?;
+
+    registration
+        .getKey(caller_uid.try_into().unwrap(), &cb)
+        .context(ks_err!("Trying to get key."))?;
+
+    rx.await.unwrap()
+}
+
+async fn store_rkpd_attestation_key_async(
+    security_level: &SecurityLevel,
+    key_blob: &[u8],
+    upgraded_blob: &[u8],
+) -> Result<()> {
+    let registration = get_rkpd_registration(security_level)
+        .await
+        .context(ks_err!("Trying to get to IRegistration service."))?;
+
+    registration
+        .storeUpgradedKey(key_blob, upgraded_blob)
+        .context(ks_err!("Failed to store upgraded blob with RKPD."))?;
+    Ok(())
+}
+
+/// Get attestation key from RKPD.
+pub fn get_rkpd_attestation_key(
+    security_level: &SecurityLevel,
+    caller_uid: u32,
+) -> Result<RemotelyProvisionedKey> {
+    let _wp = wd::watch_millis("Calling get_rkpd_attestation_key()", 500);
+    block_on(get_rkpd_attestation_key_async(security_level, caller_uid))
+}
+
+/// Store attestation key in RKPD.
+pub fn store_rkpd_attestation_key(
+    security_level: &SecurityLevel,
+    key_blob: &[u8],
+    upgraded_blob: &[u8],
+) -> Result<()> {
+    let _wp = wd::watch_millis("Calling store_rkpd_attestation_key()", 500);
+    block_on(store_rkpd_attestation_key_async(security_level, key_blob, upgraded_blob))
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use android_security_rkp_aidl::aidl::android::security::rkp::IRegistration::BnRegistration;
+    use std::sync::Arc;
+
+    #[derive(Default)]
+    struct MockRegistrationValues {
+        _key: RemotelyProvisionedKey,
+    }
+
+    #[derive(Default)]
+    struct MockRegistration(Arc<Mutex<MockRegistrationValues>>);
+
+    impl MockRegistration {
+        pub fn new_native_binder() -> Strong<dyn IRegistration> {
+            let result: Self = Default::default();
+            BnRegistration::new_binder(result, BinderFeatures::default())
+        }
+    }
+
+    impl Interface for MockRegistration {}
+
+    impl IRegistration for MockRegistration {
+        fn getKey(&self, _: i32, _: &Strong<dyn IGetKeyCallback>) -> binder::Result<()> {
+            todo!()
+        }
+
+        fn cancelGetKey(&self, _: &Strong<dyn IGetKeyCallback>) -> binder::Result<()> {
+            todo!()
+        }
+
+        fn storeUpgradedKey(&self, _: &[u8], _: &[u8]) -> binder::Result<()> {
+            todo!()
+        }
+    }
+
+    fn get_mock_registration() -> Result<binder::Strong<dyn IRegistration>> {
+        let (tx, rx) = oneshot::channel();
+        let cb = GetRegistrationCallback::new_native_binder(tx).unwrap();
+        let mock_registration = MockRegistration::new_native_binder();
+
+        assert!(cb.onSuccess(&mock_registration).is_ok());
+        block_on(rx).unwrap()
+    }
+
+    #[test]
+    fn test_get_registration_cb_success() {
+        let registration = get_mock_registration();
+        assert!(registration.is_ok());
+    }
+
+    #[test]
+    fn test_get_registration_cb_cancel() {
+        let (tx, rx) = oneshot::channel();
+        let cb = GetRegistrationCallback::new_native_binder(tx).unwrap();
+        assert!(cb.onCancel().is_ok());
+
+        let result = block_on(rx).unwrap();
+        assert_eq!(
+            result.unwrap_err().downcast::<Error>().unwrap(),
+            Error::Km(ErrorCode::OPERATION_CANCELLED)
+        );
+    }
+
+    #[test]
+    fn test_get_registration_cb_error() {
+        let (tx, rx) = oneshot::channel();
+        let cb = GetRegistrationCallback::new_native_binder(tx).unwrap();
+        assert!(cb.onError("error").is_ok());
+
+        let result = block_on(rx).unwrap();
+        assert_eq!(
+            result.unwrap_err().downcast::<Error>().unwrap(),
+            Error::Km(ErrorCode::UNKNOWN_ERROR)
+        );
+    }
+
+    #[test]
+    fn test_get_key_cb_success() {
+        let mock_key =
+            RemotelyProvisionedKey { keyBlob: vec![1, 2, 3], encodedCertChain: vec![4, 5, 6] };
+        let (tx, rx) = oneshot::channel();
+        let cb = GetKeyCallback::new_native_binder(tx).unwrap();
+        assert!(cb.onSuccess(&mock_key).is_ok());
+
+        let key = block_on(rx).unwrap().unwrap();
+        assert_eq!(key, mock_key);
+    }
+
+    #[test]
+    fn test_get_key_cb_cancel() {
+        let (tx, rx) = oneshot::channel();
+        let cb = GetKeyCallback::new_native_binder(tx).unwrap();
+        assert!(cb.onCancel().is_ok());
+
+        let result = block_on(rx).unwrap();
+        assert_eq!(
+            result.unwrap_err().downcast::<Error>().unwrap(),
+            Error::Km(ErrorCode::OPERATION_CANCELLED)
+        );
+    }
+
+    #[test]
+    fn test_get_key_cb_error() {
+        let (tx, rx) = oneshot::channel();
+        let cb = GetKeyCallback::new_native_binder(tx).unwrap();
+        assert!(cb.onError("error").is_ok());
+
+        let result = block_on(rx).unwrap();
+        assert_eq!(
+            result.unwrap_err().downcast::<Error>().unwrap(),
+            Error::Km(ErrorCode::UNKNOWN_ERROR)
+        );
+    }
+
+    #[test]
+    #[ignore]
+    fn test_get_rkpd_attestation_key() {
+        let key = get_rkpd_attestation_key(&SecurityLevel::TRUSTED_ENVIRONMENT, 0).unwrap();
+        assert!(!key.keyBlob.is_empty());
+        assert!(!key.encodedCertChain.is_empty());
+    }
+
+    #[test]
+    #[ignore]
+    fn test_get_rkpd_attestation_key_same_caller() {
+        let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
+        let caller_uid = 0;
+
+        // Multiple calls should return the same key.
+        let first_key = get_rkpd_attestation_key(&sec_level, caller_uid).unwrap();
+        let second_key = get_rkpd_attestation_key(&sec_level, caller_uid).unwrap();
+
+        assert_eq!(first_key.keyBlob, second_key.keyBlob);
+        assert_eq!(first_key.encodedCertChain, second_key.encodedCertChain);
+    }
+
+    #[test]
+    #[ignore]
+    fn test_get_rkpd_attestation_key_different_caller() {
+        let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
+
+        // Different callers should be getting different keys.
+        let first_key = get_rkpd_attestation_key(&sec_level, 1).unwrap();
+        let second_key = get_rkpd_attestation_key(&sec_level, 2).unwrap();
+
+        assert_ne!(first_key.keyBlob, second_key.keyBlob);
+        assert_ne!(first_key.encodedCertChain, second_key.encodedCertChain);
+    }
+
+    #[test]
+    #[ignore]
+    fn test_store_rkpd_attestation_key() {
+        let sec_level = SecurityLevel::TRUSTED_ENVIRONMENT;
+        let key = get_rkpd_attestation_key(&SecurityLevel::TRUSTED_ENVIRONMENT, 0).unwrap();
+
+        assert!(store_rkpd_attestation_key(&sec_level, &key.keyBlob, &key.keyBlob).is_ok());
+    }
+}
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index ae49bc8..b928fb0 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -26,6 +26,7 @@
 use crate::ks_err;
 use crate::metrics_store::log_key_creation_event_stats;
 use crate::remote_provisioning::RemProvState;
+use crate::rkpd_client::store_rkpd_attestation_key;
 use crate::super_key::{KeyBlob, SuperKeyManager};
 use crate::utils::{
     check_device_attestation_permissions, check_key_permission,
@@ -148,7 +149,7 @@
             SecurityLevel::SOFTWARE,
         ));
 
-        let creation_date = DateTime::now().context("Trying to make creation time.")?;
+        let creation_date = DateTime::now().context(ks_err!("Trying to make creation time."))?;
 
         let key = match key.domain {
             Domain::BLOB => KeyDescriptor {
@@ -616,6 +617,30 @@
                     result.certificateChain.push(attestation_certs);
                     result
                 }),
+            Some(AttestationKeyInfo::RkpdProvisioned { attestation_key, attestation_certs }) => {
+                self.upgrade_rkpd_keyblob_if_required_with(&attestation_key.keyBlob, &[], |blob| {
+                    map_km_error({
+                        let _wp = self.watch_millis(
+                            concat!(
+                                "In KeystoreSecurityLevel::generate_key (RkpdProvisioned): ",
+                                "calling generate_key.",
+                            ),
+                            5000, // Generate can take a little longer.
+                        );
+                        let dynamic_attest_key = Some(AttestationKey {
+                            keyBlob: blob.to_vec(),
+                            attestKeyParams: vec![],
+                            issuerSubjectName: attestation_key.issuerSubjectName.clone(),
+                        });
+                        self.keymint.generateKey(&params, dynamic_attest_key.as_ref())
+                    })
+                })
+                .context("While generating Key with remote provisioned attestation key.")
+                .map(|(mut result, _)| {
+                    result.certificateChain.push(attestation_certs);
+                    result
+                })
+            }
             None => map_km_error({
                 let _wp = self.watch_millis(
                     concat!(
@@ -677,7 +702,7 @@
                 KeyParameterValue::Algorithm(Algorithm::RSA)
                 | KeyParameterValue::Algorithm(Algorithm::EC) => Ok(KeyFormat::PKCS8),
                 v => Err(error::Error::Km(ErrorCode::INVALID_ARGUMENT))
-                    .context(format!("Unknown Algorithm {:?}.", v)),
+                    .context(ks_err!("Unknown Algorithm {:?}.", v)),
             })
             .context(ks_err!())?;
 
@@ -757,10 +782,10 @@
             })
             .context("Failed to load wrapping key.")?;
 
-        let (wrapping_key_blob, wrapping_blob_metadata) = wrapping_key_entry
-            .take_key_blob_info()
-            .ok_or_else(error::Error::sys)
-            .context("No km_blob after successfully loading key. This should never happen.")?;
+        let (wrapping_key_blob, wrapping_blob_metadata) =
+            wrapping_key_entry.take_key_blob_info().ok_or_else(error::Error::sys).context(
+                ks_err!("No km_blob after successfully loading key. This should never happen."),
+            )?;
 
         let wrapping_key_blob = SUPER_KEY
             .read()
@@ -888,6 +913,28 @@
         Ok((v, upgraded_blob))
     }
 
+    fn upgrade_rkpd_keyblob_if_required_with<T, F>(
+        &self,
+        key_blob: &[u8],
+        params: &[KeyParameter],
+        f: F,
+    ) -> Result<(T, Option<Vec<u8>>)>
+    where
+        F: Fn(&[u8]) -> Result<T, Error>,
+    {
+        crate::utils::upgrade_keyblob_if_required_with(
+            &*self.keymint,
+            key_blob,
+            params,
+            f,
+            |upgraded_blob| {
+                store_rkpd_attestation_key(&self.security_level, key_blob, upgraded_blob)
+                    .context(ks_err!("Failed store_rkpd_attestation_key()."))
+            },
+        )
+        .context(ks_err!())
+    }
+
     fn convert_storage_key_to_ephemeral(
         &self,
         storage_key: &KeyDescriptor,
diff --git a/keystore2/src/service.rs b/keystore2/src/service.rs
index a3e0fa5..f43ba5c 100644
--- a/keystore2/src/service.rs
+++ b/keystore2/src/service.rs
@@ -66,10 +66,7 @@
             SecurityLevel::TRUSTED_ENVIRONMENT,
             id_rotation_state.clone(),
         )
-        .context(concat!(
-            "In KeystoreService::new_native_binder: ",
-            "Trying to construct mandatory security level TEE."
-        ))?;
+        .context(ks_err!("Trying to construct mandatory security level TEE."))?;
         result.i_sec_level_by_uuid.insert(uuid, dev);
         result.uuid_by_sec_level.insert(SecurityLevel::TRUSTED_ENVIRONMENT, uuid);
 
@@ -86,9 +83,7 @@
             .set_init(move || {
                 (create_thread_local_db(), uuid_by_sec_level, LEGACY_BLOB_LOADER.clone())
             })
-            .context(
-                "In KeystoreService::new_native_binder: Trying to initialize the legacy migrator.",
-            )?;
+            .context(ks_err!("Trying to initialize the legacy migrator."))?;
 
         Ok(BnKeystoreService::new_binder(
             result,
@@ -108,8 +103,7 @@
         if let Some(dev) = self.i_sec_level_by_uuid.get(uuid) {
             Ok(dev.clone())
         } else {
-            Err(error::Error::sys())
-                .context("In get_i_sec_level_by_uuid: KeyMint instance for key not found.")
+            Err(error::Error::sys()).context(ks_err!("KeyMint instance for key not found."))
         }
     }
 
@@ -125,7 +119,7 @@
             Ok(dev.clone())
         } else {
             Err(error::Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE))
-                .context("In get_security_level: No such security level.")
+                .context(ks_err!("No such security level."))
         }
     }
 
@@ -147,12 +141,12 @@
                     )
                 })
             })
-            .context("In get_key_entry, while trying to load key info.")?;
+            .context(ks_err!("while trying to load key info."))?;
 
         let i_sec_level = if !key_entry.pure_cert() {
             Some(
                 self.get_i_sec_level_by_uuid(key_entry.km_uuid())
-                    .context("In get_key_entry: Trying to get security level proxy.")?,
+                    .context(ks_err!("Trying to get security level proxy."))?,
             )
         } else {
             None
@@ -174,7 +168,7 @@
                     .creation_date()
                     .map(|d| d.to_millis_epoch())
                     .ok_or(Error::Rc(ResponseCode::VALUE_CORRUPTED))
-                    .context("In get_key_entry: Trying to get creation date.")?,
+                    .context(ks_err!("Trying to get creation date."))?,
                 authorizations: key_parameters_to_authorizations(key_entry.into_key_parameters()),
             },
         })
@@ -197,10 +191,7 @@
                     KeyType::Client,
                     KeyEntryLoadBits::NONE,
                     caller_uid,
-                    |k, av| {
-                        check_key_permission(KeyPerm::Update, k, &av)
-                            .context("In update_subcomponent.")
-                    },
+                    |k, av| check_key_permission(KeyPerm::Update, k, &av).context(ks_err!()),
                 )
             }) {
                 Err(e) => match e.root_cause().downcast_ref::<Error>() {
@@ -209,7 +200,7 @@
                 },
                 Ok(v) => Ok(Some(v)),
             }
-            .context("Failed to load key entry.")?;
+            .context(ks_err!("Failed to load key entry."))?;
 
             let mut db = db.borrow_mut();
             if let Some((key_id_guard, _key_entry)) = entry {
@@ -256,7 +247,7 @@
             .context("Failed to insert new certificate.")?;
             Ok(())
         })
-        .context("In update_subcomponent.")
+        .context(ks_err!())
     }
 
     fn list_entries(&self, domain: Domain, namespace: i64) -> Result<Vec<KeyDescriptor>> {
diff --git a/keystore2/src/super_key.rs b/keystore2/src/super_key.rs
index dd22d8b..f000213 100644
--- a/keystore2/src/super_key.rs
+++ b/keystore2/src/super_key.rs
@@ -25,6 +25,7 @@
     error::Error,
     error::ResponseCode,
     key_parameter::{KeyParameter, KeyParameterValue},
+    ks_err,
     legacy_blob::LegacyBlobLoader,
     legacy_importer::LegacyImporter,
     raw_device::KeyMintDevice,
@@ -156,19 +157,17 @@
 impl AesGcm for SuperKey {
     fn decrypt(&self, data: &[u8], iv: &[u8], tag: &[u8]) -> Result<ZVec> {
         if self.algorithm == SuperEncryptionAlgorithm::Aes256Gcm {
-            aes_gcm_decrypt(data, iv, tag, &self.key)
-                .context("In SuperKey::decrypt: Decryption failed.")
+            aes_gcm_decrypt(data, iv, tag, &self.key).context(ks_err!("Decryption failed."))
         } else {
-            Err(Error::sys()).context("In SuperKey::decrypt: Key is not an AES key.")
+            Err(Error::sys()).context(ks_err!("Key is not an AES key."))
         }
     }
 
     fn encrypt(&self, plaintext: &[u8]) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>)> {
         if self.algorithm == SuperEncryptionAlgorithm::Aes256Gcm {
-            aes_gcm_encrypt(plaintext, &self.key)
-                .context("In SuperKey::encrypt: Encryption failed.")
+            aes_gcm_encrypt(plaintext, &self.key).context(ks_err!("Encryption failed."))
         } else {
-            Err(Error::sys()).context("In SuperKey::encrypt: Key is not an AES key.")
+            Err(Error::sys()).context(ks_err!("Key is not an AES key."))
         }
     }
 }
@@ -203,7 +202,7 @@
             .as_ref()
             .map(|(key_blob, _)| KeyBlob::Ref(key_blob))
             .ok_or(Error::Rc(ResponseCode::KEY_NOT_FOUND))
-            .context("In LockedKey::decrypt: Missing key blob info.")?;
+            .context(ks_err!("Missing key blob info."))?;
         let key_params = vec![
             KeyParameterValue::Algorithm(Algorithm::AES),
             KeyParameterValue::KeySize(256),
@@ -270,10 +269,7 @@
             self.key_index.insert(id, Arc::downgrade(super_key));
             Ok(())
         } else {
-            Err(Error::sys()).context(format!(
-                "In add_key_to_key_index: cannot add key with ID {:?}",
-                super_key.id
-            ))
+            Err(Error::sys()).context(ks_err!("Cannot add key with ID {:?}", super_key.id))
         }
     }
 }
@@ -290,8 +286,8 @@
             log::info!("In set_up_boot_level_cache: called for a second time");
             return Ok(());
         }
-        let level_zero_key = get_level_zero_key(db)
-            .context("In set_up_boot_level_cache: get_level_zero_key failed")?;
+        let level_zero_key =
+            get_level_zero_key(db).context(ks_err!("get_level_zero_key failed"))?;
         skm_guard.data.boot_level_key_cache =
             Some(Mutex::new(BootLevelKeyCache::new(level_zero_key)));
         log::info!("Starting boot level watcher.");
@@ -307,11 +303,11 @@
     /// Blocks waiting for system property changes, so must be run in its own thread.
     fn watch_boot_level(skm: Arc<RwLock<Self>>) -> Result<()> {
         let mut w = PropertyWatcher::new("keystore.boot_level")
-            .context("In watch_boot_level: PropertyWatcher::new failed")?;
+            .context(ks_err!("PropertyWatcher::new failed"))?;
         loop {
             let level = w
                 .read(|_n, v| v.parse::<usize>().map_err(std::convert::Into::into))
-                .context("In watch_boot_level: read of property failed")?;
+                .context(ks_err!("read of property failed"))?;
 
             // This scope limits the skm_guard life, so we don't hold the skm_guard while
             // waiting.
@@ -322,14 +318,14 @@
                     .boot_level_key_cache
                     .as_mut()
                     .ok_or_else(Error::sys)
-                    .context("In watch_boot_level: Boot level cache not initialized")?
+                    .context(ks_err!("Boot level cache not initialized"))?
                     .get_mut()
                     .unwrap();
                 if level < MAX_MAX_BOOT_LEVEL {
                     log::info!("Read keystore.boot_level value {}", level);
                     boot_level_key_cache
                         .advance_boot_level(level)
-                        .context("In watch_boot_level: advance_boot_level failed")?;
+                        .context(ks_err!("advance_boot_level failed"))?;
                 } else {
                     log::info!(
                         "keystore.boot_level {} hits maximum {}, finishing.",
@@ -340,7 +336,7 @@
                     break;
                 }
             }
-            w.wait().context("In watch_boot_level: property wait failed")?;
+            w.wait().context(ks_err!("property wait failed"))?;
         }
         Ok(())
     }
@@ -363,7 +359,7 @@
     ) -> Result<()> {
         self.data
             .add_key_to_key_index(&super_key)
-            .context("In install_per_boot_key_for_user: add_key_to_key_index failed")?;
+            .context(ks_err!("add_key_to_key_index failed"))?;
         self.data.user_keys.entry(user).or_default().per_boot = Some(super_key);
         Ok(())
     }
@@ -379,7 +375,7 @@
                 .as_ref()
                 .map(|b| b.lock().unwrap().aes_key(*level as usize))
                 .transpose()
-                .context("In lookup_key: aes_key failed")?
+                .context(ks_err!("aes_key failed"))?
                 .flatten()
                 .map(|key| {
                     Arc::new(SuperKey {
@@ -425,12 +421,12 @@
                     // For backward compatibility we need to check if there is a super key present.
                     let super_key = legacy_blob_loader
                         .load_super_key(user, pw)
-                        .context("In create_new_key: Failed to load legacy key blob.")?;
+                        .context(ks_err!("Failed to load legacy key blob."))?;
                     let super_key = match super_key {
                         None => {
                             // No legacy file was found. So we generate a new key.
                             generate_aes256_key()
-                                .context("In create_new_key: Failed to generate AES 256 key.")?
+                                .context(ks_err!("Failed to generate AES 256 key."))?
                         }
                         Some(key) => key,
                     };
@@ -442,10 +438,10 @@
                     Self::encrypt_with_password(&super_key, pw).context("In create_new_key.")
                 },
             )
-            .context("In unlock_user_key: Failed to get key id.")?;
+            .context(ks_err!("Failed to get key id."))?;
 
         self.populate_cache_from_super_key_blob(user, USER_SUPER_KEY.algorithm, entry, pw)
-            .context("In unlock_user_key.")?;
+            .context(ks_err!())?;
         Ok(())
     }
 
@@ -459,12 +455,12 @@
         Ok(if let Some(key_id) = SuperKeyIdentifier::from_metadata(metadata) {
             let super_key = self
                 .lookup_key(&key_id)
-                .context("In unwrap_key: lookup_key failed")?
+                .context(ks_err!("lookup_key failed"))?
                 .ok_or(Error::Rc(ResponseCode::LOCKED))
-                .context("In unwrap_key: Required super decryption key is not in memory.")?;
+                .context(ks_err!("Required super decryption key is not in memory."))?;
             KeyBlob::Sensitive {
                 key: Self::unwrap_key_with_key(blob, metadata, &super_key)
-                    .context("In unwrap_key: unwrap_key_with_key failed")?,
+                    .context(ks_err!("unwrap_key_with_key failed"))?,
                 reencrypt_with: super_key.reencrypt_with.as_ref().unwrap_or(&super_key).clone(),
                 force_reencrypt: super_key.reencrypt_with.is_some(),
             }
@@ -477,14 +473,11 @@
     fn unwrap_key_with_key(blob: &[u8], metadata: &BlobMetaData, key: &SuperKey) -> Result<ZVec> {
         match key.algorithm {
             SuperEncryptionAlgorithm::Aes256Gcm => match (metadata.iv(), metadata.aead_tag()) {
-                (Some(iv), Some(tag)) => key
-                    .decrypt(blob, iv, tag)
-                    .context("In unwrap_key_with_key: Failed to decrypt the key blob."),
-                (iv, tag) => Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
-                    concat!(
-                        "In unwrap_key_with_key: Key has incomplete metadata.",
-                        "Present: iv: {}, aead_tag: {}."
-                    ),
+                (Some(iv), Some(tag)) => {
+                    key.decrypt(blob, iv, tag).context(ks_err!("Failed to decrypt the key blob."))
+                }
+                (iv, tag) => Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(ks_err!(
+                    "Key has incomplete metadata. Present: iv: {}, aead_tag: {}.",
                     iv.is_some(),
                     tag.is_some(),
                 )),
@@ -494,14 +487,12 @@
                     (Some(public_key), Some(salt), Some(iv), Some(aead_tag)) => {
                         ECDHPrivateKey::from_private_key(&key.key)
                             .and_then(|k| k.decrypt_message(public_key, salt, iv, blob, aead_tag))
-                            .context(
-                                "In unwrap_key_with_key: Failed to decrypt the key blob with ECDH.",
-                            )
+                            .context(ks_err!("Failed to decrypt the key blob with ECDH."))
                     }
                     (public_key, salt, iv, aead_tag) => {
-                        Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
+                        Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(ks_err!(
                             concat!(
-                                "In unwrap_key_with_key: Key has incomplete metadata.",
+                                "Key has incomplete metadata. ",
                                 "Present: public_key: {}, salt: {}, iv: {}, aead_tag: {}."
                             ),
                             public_key.is_some(),
@@ -526,14 +517,12 @@
     ) -> Result<bool> {
         let key_in_db = db
             .key_exists(Domain::APP, user_id as u64 as i64, USER_SUPER_KEY.alias, KeyType::Super)
-            .context("In super_key_exists_in_db_for_user.")?;
+            .context(ks_err!())?;
 
         if key_in_db {
             Ok(key_in_db)
         } else {
-            legacy_importer
-                .has_super_key(user_id)
-                .context("In super_key_exists_in_db_for_user: Trying to query legacy db.")
+            legacy_importer.has_super_key(user_id).context(ks_err!("Trying to query legacy db."))
         }
     }
 
@@ -550,13 +539,13 @@
         let alias = &USER_SUPER_KEY;
         let result = legacy_importer
             .with_try_import_super_key(user_id, pw, || db.load_super_key(alias, user_id))
-            .context("In check_and_unlock_super_key. Failed to load super key")?;
+            .context(ks_err!("Failed to load super key"))?;
 
         match result {
             Some((_, entry)) => {
                 let super_key = self
                     .populate_cache_from_super_key_blob(user_id, alias.algorithm, entry, pw)
-                    .context("In check_and_unlock_super_key.")?;
+                    .context(ks_err!())?;
                 Ok(UserState::LskfUnlocked(super_key))
             }
             None => Ok(UserState::Uninitialized),
@@ -578,17 +567,17 @@
     ) -> Result<UserState> {
         let super_key_exists_in_db = self
             .super_key_exists_in_db_for_user(db, legacy_importer, user_id)
-            .context("In check_and_initialize_super_key. Failed to check if super key exists.")?;
+            .context(ks_err!("Failed to check if super key exists."))?;
         if super_key_exists_in_db {
             Ok(UserState::LskfLocked)
         } else if let Some(pw) = pw {
             // Generate a new super key.
-            let super_key = generate_aes256_key()
-                .context("In check_and_initialize_super_key: Failed to generate AES 256 key.")?;
+            let super_key =
+                generate_aes256_key().context(ks_err!("Failed to generate AES 256 key."))?;
             // Derive an AES256 key from the password and re-encrypt the super key
             // before we insert it in the database.
-            let (encrypted_super_key, blob_metadata) = Self::encrypt_with_password(&super_key, pw)
-                .context("In check_and_initialize_super_key.")?;
+            let (encrypted_super_key, blob_metadata) =
+                Self::encrypt_with_password(&super_key, pw).context(ks_err!())?;
 
             let key_entry = db
                 .store_super_key(
@@ -598,7 +587,7 @@
                     &blob_metadata,
                     &KeyMetaData::new(),
                 )
-                .context("In check_and_initialize_super_key. Failed to store super key.")?;
+                .context(ks_err!("Failed to store super key."))?;
 
             let super_key = self
                 .populate_cache_from_super_key_blob(
@@ -607,7 +596,7 @@
                     key_entry,
                     pw,
                 )
-                .context("In check_and_initialize_super_key.")?;
+                .context(ks_err!())?;
             Ok(UserState::LskfUnlocked(super_key))
         } else {
             Ok(UserState::Uninitialized)
@@ -623,9 +612,7 @@
         pw: &Password,
     ) -> Result<Arc<SuperKey>> {
         let super_key = Self::extract_super_key_from_key_entry(algorithm, entry, pw, None)
-            .context(
-                "In populate_cache_from_super_key_blob. Failed to extract super key from key entry",
-            )?;
+            .context(ks_err!("Failed to extract super key from key entry"))?;
         self.install_per_boot_key_for_user(user_id, super_key.clone())?;
         Ok(super_key)
     }
@@ -646,20 +633,19 @@
             ) {
                 (Some(&EncryptedBy::Password), Some(salt), Some(iv), Some(tag)) => {
                     // Note that password encryption is AES no matter the value of algorithm.
-                    let key = pw.derive_key(salt, AES_256_KEY_LENGTH).context(
-                        "In extract_super_key_from_key_entry: Failed to generate key from password.",
-                    )?;
+                    let key = pw
+                        .derive_key(salt, AES_256_KEY_LENGTH)
+                        .context(ks_err!("Failed to generate key from password."))?;
 
-                    aes_gcm_decrypt(blob, iv, tag, &key).context(
-                        "In extract_super_key_from_key_entry: Failed to decrypt key blob.",
-                    )?
+                    aes_gcm_decrypt(blob, iv, tag, &key)
+                        .context(ks_err!("Failed to decrypt key blob."))?
                 }
                 (enc_by, salt, iv, tag) => {
-                    return Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(format!(
+                    return Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(ks_err!(
                         concat!(
-                        "In extract_super_key_from_key_entry: Super key has incomplete metadata.",
-                        "encrypted_by: {:?}; Present: salt: {}, iv: {}, aead_tag: {}."
-                    ),
+                            "Super key has incomplete metadata.",
+                            "encrypted_by: {:?}; Present: salt: {}, iv: {}, aead_tag: {}."
+                        ),
                         enc_by,
                         salt.is_some(),
                         iv.is_some(),
@@ -674,8 +660,7 @@
                 reencrypt_with,
             }))
         } else {
-            Err(Error::Rc(ResponseCode::VALUE_CORRUPTED))
-                .context("In extract_super_key_from_key_entry: No key blob info.")
+            Err(Error::Rc(ResponseCode::VALUE_CORRUPTED)).context(ks_err!("No key blob info."))
         }
     }
 
@@ -687,12 +672,12 @@
         let salt = generate_salt().context("In encrypt_with_password: Failed to generate salt.")?;
         let derived_key = pw
             .derive_key(&salt, AES_256_KEY_LENGTH)
-            .context("In encrypt_with_password: Failed to derive password.")?;
+            .context(ks_err!("Failed to derive password."))?;
         let mut metadata = BlobMetaData::new();
         metadata.add(BlobMetaEntry::EncryptedBy(EncryptedBy::Password));
         metadata.add(BlobMetaEntry::Salt(salt));
         let (encrypted_key, iv, tag) = aes_gcm_encrypt(super_key, &derived_key)
-            .context("In encrypt_with_password: Failed to encrypt new super key.")?;
+            .context(ks_err!("Failed to encrypt new super key."))?;
         metadata.add(BlobMetaEntry::Iv(iv));
         metadata.add(BlobMetaEntry::AeadTag(tag));
         Ok((encrypted_key, metadata))
@@ -711,17 +696,17 @@
     ) -> Result<(Vec<u8>, BlobMetaData)> {
         match self
             .get_user_state(db, legacy_importer, user_id)
-            .context("In super_encrypt. Failed to get user state.")?
+            .context(ks_err!("Failed to get user state."))?
         {
             UserState::LskfUnlocked(super_key) => {
                 Self::encrypt_with_aes_super_key(key_blob, &super_key)
-                    .context("In super_encrypt_on_key_init. Failed to encrypt the key.")
+                    .context(ks_err!("Failed to encrypt the key."))
             }
             UserState::LskfLocked => {
-                Err(Error::Rc(ResponseCode::LOCKED)).context("In super_encrypt. Device is locked.")
+                Err(Error::Rc(ResponseCode::LOCKED)).context(ks_err!("Device is locked."))
             }
             UserState::Uninitialized => Err(Error::Rc(ResponseCode::UNINITIALIZED))
-                .context("In super_encrypt. LSKF is not setup for the user."),
+                .context(ks_err!("LSKF is not setup for the user.")),
         }
     }
 
@@ -733,12 +718,11 @@
         super_key: &SuperKey,
     ) -> Result<(Vec<u8>, BlobMetaData)> {
         if super_key.algorithm != SuperEncryptionAlgorithm::Aes256Gcm {
-            return Err(Error::sys())
-                .context("In encrypt_with_aes_super_key: unexpected algorithm");
+            return Err(Error::sys()).context(ks_err!("unexpected algorithm"));
         }
         let mut metadata = BlobMetaData::new();
         let (encrypted_key, iv, tag) = aes_gcm_encrypt(key_blob, &(super_key.key))
-            .context("In encrypt_with_aes_super_key: Failed to encrypt new super key.")?;
+            .context(ks_err!("Failed to encrypt new super key."))?;
         metadata.add(BlobMetaEntry::Iv(iv));
         metadata.add(BlobMetaEntry::AeadTag(tag));
         super_key.id.add_to_metadata(&mut metadata);
@@ -762,37 +746,29 @@
             SuperEncryptionType::None => Ok((key_blob.to_vec(), BlobMetaData::new())),
             SuperEncryptionType::LskfBound => self
                 .super_encrypt_on_key_init(db, legacy_importer, user_id, key_blob)
-                .context(concat!(
-                    "In handle_super_encryption_on_key_init. ",
-                    "Failed to super encrypt with LskfBound key."
-                )),
+                .context(ks_err!("Failed to super encrypt with LskfBound key.")),
             SuperEncryptionType::ScreenLockBound => {
                 let entry =
                     self.data.user_keys.get(&user_id).and_then(|e| e.screen_lock_bound.as_ref());
                 if let Some(super_key) = entry {
-                    Self::encrypt_with_aes_super_key(key_blob, super_key).context(concat!(
-                        "In handle_super_encryption_on_key_init. ",
-                        "Failed to encrypt with ScreenLockBound key."
-                    ))
+                    Self::encrypt_with_aes_super_key(key_blob, super_key)
+                        .context(ks_err!("Failed to encrypt with ScreenLockBound key."))
                 } else {
                     // Symmetric key is not available, use public key encryption
-                    let loaded =
-                        db.load_super_key(&USER_SCREEN_LOCK_BOUND_P521_KEY, user_id).context(
-                            "In handle_super_encryption_on_key_init: load_super_key failed.",
-                        )?;
-                    let (key_id_guard, key_entry) = loaded.ok_or_else(Error::sys).context(
-                        "In handle_super_encryption_on_key_init: User ECDH key missing.",
-                    )?;
-                    let public_key =
-                        key_entry.metadata().sec1_public_key().ok_or_else(Error::sys).context(
-                            "In handle_super_encryption_on_key_init: sec1_public_key missing.",
-                        )?;
+                    let loaded = db
+                        .load_super_key(&USER_SCREEN_LOCK_BOUND_P521_KEY, user_id)
+                        .context(ks_err!("load_super_key failed."))?;
+                    let (key_id_guard, key_entry) =
+                        loaded.ok_or_else(Error::sys).context(ks_err!("User ECDH key missing."))?;
+                    let public_key = key_entry
+                        .metadata()
+                        .sec1_public_key()
+                        .ok_or_else(Error::sys)
+                        .context(ks_err!("sec1_public_key missing."))?;
                     let mut metadata = BlobMetaData::new();
                     let (ephem_key, salt, iv, encrypted_key, aead_tag) =
-                        ECDHPrivateKey::encrypt_message(public_key, key_blob).context(concat!(
-                            "In handle_super_encryption_on_key_init: ",
-                            "ECDHPrivateKey::encrypt_message failed."
-                        ))?;
+                        ECDHPrivateKey::encrypt_message(public_key, key_blob)
+                            .context(ks_err!("ECDHPrivateKey::encrypt_message failed."))?;
                     metadata.add(BlobMetaEntry::PublicKey(ephem_key));
                     metadata.add(BlobMetaEntry::Salt(salt));
                     metadata.add(BlobMetaEntry::Iv(iv));
@@ -806,13 +782,11 @@
                 let key_id = SuperKeyIdentifier::BootLevel(level);
                 let super_key = self
                     .lookup_key(&key_id)
-                    .context("In handle_super_encryption_on_key_init: lookup_key failed")?
+                    .context(ks_err!("lookup_key failed"))?
                     .ok_or(Error::Rc(ResponseCode::LOCKED))
-                    .context("In handle_super_encryption_on_key_init: Boot stage key absent")?;
-                Self::encrypt_with_aes_super_key(key_blob, &super_key).context(concat!(
-                    "In handle_super_encryption_on_key_init: ",
-                    "Failed to encrypt with BootLevel key."
-                ))
+                    .context(ks_err!("Boot stage key absent"))?;
+                Self::encrypt_with_aes_super_key(key_blob, &super_key)
+                    .context(ks_err!("Failed to encrypt with BootLevel key."))
             }
         }
     }
@@ -828,7 +802,7 @@
             KeyBlob::Sensitive { reencrypt_with: super_key, .. } => {
                 let (key, metadata) =
                     Self::encrypt_with_aes_super_key(key_after_upgrade, super_key)
-                        .context("In reencrypt_if_required: Failed to re-super-encrypt key.")?;
+                        .context(ks_err!("Failed to re-super-encrypt key."))?;
                 Ok((KeyBlob::NonSensitive(key), Some(metadata)))
             }
             _ => Ok((KeyBlob::Ref(key_after_upgrade), None)),
@@ -857,28 +831,22 @@
         } else {
             let (super_key, public_key) = match key_type.algorithm {
                 SuperEncryptionAlgorithm::Aes256Gcm => (
-                    generate_aes256_key()
-                        .context("In get_or_create_super_key: Failed to generate AES 256 key.")?,
+                    generate_aes256_key().context(ks_err!("Failed to generate AES 256 key."))?,
                     None,
                 ),
                 SuperEncryptionAlgorithm::EcdhP521 => {
                     let key = ECDHPrivateKey::generate()
-                        .context("In get_or_create_super_key: Failed to generate ECDH key")?;
+                        .context(ks_err!("Failed to generate ECDH key"))?;
                     (
-                        key.private_key()
-                            .context("In get_or_create_super_key: private_key failed")?,
-                        Some(
-                            key.public_key()
-                                .context("In get_or_create_super_key: public_key failed")?,
-                        ),
+                        key.private_key().context(ks_err!("private_key failed"))?,
+                        Some(key.public_key().context(ks_err!("public_key failed"))?),
                     )
                 }
             };
             // Derive an AES256 key from the password and re-encrypt the super key
             // before we insert it in the database.
             let (encrypted_super_key, blob_metadata) =
-                Self::encrypt_with_password(&super_key, password)
-                    .context("In get_or_create_super_key.")?;
+                Self::encrypt_with_password(&super_key, password).context(ks_err!())?;
             let mut key_metadata = KeyMetaData::new();
             if let Some(pk) = public_key {
                 key_metadata.add(KeyMetaEntry::Sec1PublicKey(pk));
@@ -891,7 +859,7 @@
                     &blob_metadata,
                     &key_metadata,
                 )
-                .context("In get_or_create_super_key. Failed to store super key.")?;
+                .context(ks_err!("Failed to store super key."))?;
             Ok(Arc::new(SuperKey {
                 algorithm: key_type.algorithm,
                 key: super_key,
@@ -926,7 +894,7 @@
             screen_lock_bound
         } else {
             self.get_or_create_super_key(db, user_id, &USER_SCREEN_LOCK_BOUND_KEY, password, None)
-                .context("In unlock_screen_lock_bound_key: Trying to get or create symmetric key.")?
+                .context(ks_err!("Trying to get or create symmetric key."))?
         };
 
         let ecdh = if let Some(screen_lock_bound_private) = screen_lock_bound_private {
@@ -941,7 +909,7 @@
                 password,
                 Some(aes.clone()),
             )
-            .context("In unlock_screen_lock_bound_key: Trying to get or create asymmetric key.")?
+            .context(ks_err!("Trying to get or create asymmetric key."))?
         };
 
         self.data.add_key_to_key_index(&aes)?;
@@ -974,7 +942,7 @@
                     let encrypting_key = generate_aes256_key()?;
                     let km_dev: KeyMintDevice =
                         KeyMintDevice::get(SecurityLevel::TRUSTED_ENVIRONMENT)
-                            .context("In lock_screen_lock_bound_key: KeyMintDevice::get failed")?;
+                            .context(ks_err!("KeyMintDevice::get failed"))?;
                     let mut key_params = vec![
                         KeyParameterValue::Algorithm(Algorithm::AES),
                         KeyParameterValue::KeySize(256),
@@ -1046,9 +1014,9 @@
                     AID_KEYSTORE,
                     |_, _| Ok(()),
                 )
-                .context("In try_unlock_user_with_biometric: load_key_entry failed")?;
+                .context(ks_err!("load_key_entry failed"))?;
             let km_dev: KeyMintDevice = KeyMintDevice::get(SecurityLevel::TRUSTED_ENVIRONMENT)
-                .context("In try_unlock_user_with_biometric: KeyMintDevice::get failed")?;
+                .context(ks_err!("KeyMintDevice::get failed"))?;
             for sid in &biometric.sids {
                 if let Some((auth_token_entry, _)) = db.find_auth_token_entry(|entry| {
                     entry.auth_token().userId == *sid || entry.auth_token().authenticatorId == *sid
@@ -1078,14 +1046,11 @@
                             entry.screen_lock_bound_private = Some(slbp.clone());
                             self.data.add_key_to_key_index(&slb)?;
                             self.data.add_key_to_key_index(&slbp)?;
-                            log::info!(concat!(
-                                "In try_unlock_user_with_biometric: ",
-                                "Successfully unlocked with biometric"
-                            ));
+                            log::info!("Successfully unlocked with biometric");
                             return Ok(());
                         }
                         Err(e) => {
-                            log::warn!("In try_unlock_user_with_biometric: attempt failed: {:?}", e)
+                            log::warn!("attempt failed: {:?}", e)
                         }
                     }
                 }
@@ -1110,7 +1075,7 @@
                 // If so, return locked user state.
                 if self
                     .super_key_exists_in_db_for_user(db, legacy_importer, user_id)
-                    .context("In get_user_state.")?
+                    .context(ks_err!())?
                 {
                     Ok(UserState::LskfLocked)
                 } else {
@@ -1141,9 +1106,8 @@
             Some(_) if password.is_none() => {
                 // Transitioning to swiping, delete only the super key in database and cache,
                 // and super-encrypted keys in database (and in KM).
-                self.reset_user(db, legacy_importer, user_id, true).context(
-                    "In reset_or_init_user_and_get_user_state: Trying to delete keys from the db.",
-                )?;
+                self.reset_user(db, legacy_importer, user_id, true)
+                    .context(ks_err!("Trying to delete keys from the db."))?;
                 // Lskf is now removed in Keystore.
                 Ok(UserState::Uninitialized)
             }
@@ -1174,7 +1138,7 @@
     ) -> Result<UserState> {
         match self.get_per_boot_key_by_user_id_internal(user_id) {
             Some(super_key) => {
-                log::info!("In unlock_and_get_user_state. Trying to unlock when already unlocked.");
+                log::info!("Trying to unlock when already unlocked.");
                 Ok(UserState::LskfUnlocked(super_key))
             }
             None => {
@@ -1183,7 +1147,7 @@
                 // Otherwise, try to unlock the super key and if successful,
                 // return LskfUnlocked.
                 self.check_and_unlock_super_key(db, legacy_importer, user_id, password)
-                    .context("In unlock_and_get_user_state. Failed to unlock super key.")
+                    .context(ks_err!("Failed to unlock super key."))
             }
         }
     }
@@ -1201,9 +1165,9 @@
         // Mark keys created on behalf of the user as unreferenced.
         legacy_importer
             .bulk_delete_user(user_id, keep_non_super_encrypted_keys)
-            .context("In reset_user: Trying to delete legacy keys.")?;
+            .context(ks_err!("Trying to delete legacy keys."))?;
         db.unbind_keys_for_user(user_id, keep_non_super_encrypted_keys)
-            .context("In reset user. Error in unbinding keys.")?;
+            .context(ks_err!("Error in unbinding keys."))?;
 
         // Delete super key in cache, if exists.
         self.forget_all_keys_for_user(user_id);
diff --git a/keystore2/src/utils.rs b/keystore2/src/utils.rs
index 9db2eb9..75d98e2 100644
--- a/keystore2/src/utils.rs
+++ b/keystore2/src/utils.rs
@@ -17,6 +17,7 @@
 
 use crate::error::{map_binder_status, map_km_error, Error, ErrorCode};
 use crate::key_parameter::KeyParameter;
+use crate::ks_err;
 use crate::permission;
 use crate::permission::{KeyPerm, KeyPermSet, KeystorePerm};
 use crate::{
@@ -51,9 +52,9 @@
 pub fn check_keystore_permission(perm: KeystorePerm) -> anyhow::Result<()> {
     ThreadState::with_calling_sid(|calling_sid| {
         permission::check_keystore_permission(
-            calling_sid.ok_or_else(Error::sys).context(
-                "In check_keystore_permission: Cannot check permission without calling_sid.",
-            )?,
+            calling_sid
+                .ok_or_else(Error::sys)
+                .context(ks_err!("Cannot check permission without calling_sid."))?,
             perm,
         )
     })
@@ -65,9 +66,9 @@
 pub fn check_grant_permission(access_vec: KeyPermSet, key: &KeyDescriptor) -> anyhow::Result<()> {
     ThreadState::with_calling_sid(|calling_sid| {
         permission::check_grant_permission(
-            calling_sid.ok_or_else(Error::sys).context(
-                "In check_grant_permission: Cannot check permission without calling_sid.",
-            )?,
+            calling_sid
+                .ok_or_else(Error::sys)
+                .context(ks_err!("Cannot check permission without calling_sid."))?,
             access_vec,
             key,
         )
@@ -87,7 +88,7 @@
             ThreadState::get_calling_uid(),
             calling_sid
                 .ok_or_else(Error::sys)
-                .context("In check_key_permission: Cannot check permission without calling_sid.")?,
+                .context(ks_err!("Cannot check permission without calling_sid."))?,
             perm,
             key,
             access_vector,
@@ -103,6 +104,7 @@
             | Tag::ATTESTATION_ID_MEID
             | Tag::ATTESTATION_ID_SERIAL
             | Tag::DEVICE_UNIQUE_ATTESTATION
+            | Tag::ATTESTATION_ID_SECOND_IMEI
     )
 }
 
@@ -135,14 +137,12 @@
             ThreadState::get_calling_uid() as i32,
         )
     };
-    let has_permissions = map_binder_status(binder_result)
-        .context("In check_device_attestation_permissions: checkPermission failed")?;
+    let has_permissions =
+        map_binder_status(binder_result).context(ks_err!("checkPermission failed"))?;
     match has_permissions {
         true => Ok(()),
-        false => Err(Error::Km(ErrorCode::CANNOT_ATTEST_IDS)).context(concat!(
-            "In check_device_attestation_permissions: ",
-            "caller does not have the permission to attest device IDs"
-        )),
+        false => Err(Error::Km(ErrorCode::CANNOT_ATTEST_IDS))
+            .context(ks_err!("caller does not have the permission to attest device IDs")),
     }
 }
 
@@ -189,18 +189,15 @@
                 );
                 map_km_error(km_dev.upgradeKey(key_blob, upgrade_params))
             }
-            .context("In utils::upgrade_keyblob_if_required_with: Upgrade failed.")?;
+            .context(ks_err!("Upgrade failed."))?;
 
-            new_blob_handler(&upgraded_blob)
-                .context("In utils::upgrade_keyblob_if_required_with: calling new_blob_handler.")?;
+            new_blob_handler(&upgraded_blob).context(ks_err!("calling new_blob_handler."))?;
 
             km_op(&upgraded_blob)
                 .map(|v| (v, Some(upgraded_blob)))
-                .context("In utils::upgrade_keyblob_if_required_with: Calling km_op after upgrade.")
+                .context(ks_err!("Calling km_op after upgrade."))
         }
-        r => r
-            .map(|v| (v, None))
-            .context("In utils::upgrade_keyblob_if_required_with: Calling km_op."),
+        r => r.map(|v| (v, None)).context(ks_err!("Calling km_op.")),
     }
 }
 
@@ -270,12 +267,12 @@
     result.append(
         &mut LEGACY_IMPORTER
             .list_uid(domain, namespace)
-            .context("In list_key_entries: Trying to list legacy keys.")?,
+            .context(ks_err!("Trying to list legacy keys."))?,
     );
     result.append(
         &mut db
             .list(domain, namespace, KeyType::Client)
-            .context("In list_key_entries: Trying to list keystore database.")?,
+            .context(ks_err!("Trying to list keystore database."))?,
     );
     result.sort_unstable();
     result.dedup();
@@ -333,12 +330,11 @@
 
 impl<T: AesGcmKey> AesGcm for T {
     fn decrypt(&self, data: &[u8], iv: &[u8], tag: &[u8]) -> Result<ZVec> {
-        aes_gcm_decrypt(data, iv, tag, self.key())
-            .context("In AesGcm<T>::decrypt: Decryption failed")
+        aes_gcm_decrypt(data, iv, tag, self.key()).context(ks_err!("Decryption failed"))
     }
 
     fn encrypt(&self, plaintext: &[u8]) -> Result<(Vec<u8>, Vec<u8>, Vec<u8>)> {
-        aes_gcm_encrypt(plaintext, self.key()).context("In AesGcm<T>::encrypt: Encryption failed.")
+        aes_gcm_encrypt(plaintext, self.key()).context(ks_err!("Encryption failed."))
     }
 }
 
diff --git a/ondevice-signing/VerityUtils.cpp b/ondevice-signing/VerityUtils.cpp
index d5c7299..0b631da 100644
--- a/ondevice-signing/VerityUtils.cpp
+++ b/ondevice-signing/VerityUtils.cpp
@@ -29,14 +29,12 @@
 #include "android-base/errors.h"
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/result.h>
 #include <android-base/unique_fd.h>
 #include <asm/byteorder.h>
 #include <libfsverity.h>
 #include <linux/fsverity.h>
 
-#include "CertUtils.h"
-#include "SigningKey.h"
-
 #define FS_VERITY_MAX_DIGEST_SIZE 64
 
 using android::base::ErrnoError;
@@ -59,23 +57,6 @@
     return ss.str();
 }
 
-static std::vector<uint8_t> fromHex(std::string_view hex) {
-    if (hex.size() % 2 != 0) {
-        return {};
-    }
-    std::vector<uint8_t> result;
-    result.reserve(hex.size() / 2);
-    for (size_t i = 0; i < hex.size(); i += 2) {
-        uint8_t byte;
-        auto conversion_result = std::from_chars(&hex[i], &hex[i + 2], byte, 16);
-        if (conversion_result.ptr != &hex[i + 2] || conversion_result.ec != std::errc()) {
-            return {};
-        }
-        result.push_back(byte);
-    }
-    return result;
-}
-
 static int read_callback(void* file, void* buf, size_t count) {
     int* fd = (int*)file;
     if (TEMP_FAILURE_RETRY(read(*fd, buf, count)) < 0) return errno ? -errno : -EIO;
@@ -163,28 +144,9 @@
 
 }  // namespace
 
-static Result<std::vector<uint8_t>> signDigest(const SigningKey& key,
-                                               const std::vector<uint8_t>& digest) {
-    auto d = makeUniqueWithTrailingData<fsverity_formatted_digest>(digest.size());
-
-    memcpy(d->magic, "FSVerity", 8);
-    d->digest_algorithm = __cpu_to_le16(FS_VERITY_HASH_ALG_SHA256);
-    d->digest_size = __cpu_to_le16(digest.size());
-    memcpy(d->digest, digest.data(), digest.size());
-
-    auto signed_digest = key.sign(std::string((char*)d.get(), sizeof(*d) + digest.size()));
-    if (!signed_digest.ok()) {
-        return signed_digest.error();
-    }
-
-    return std::vector<uint8_t>(signed_digest->begin(), signed_digest->end());
-}
-
-static Result<void> enableFsVerity(int fd, std::span<uint8_t> pkcs7) {
+static Result<void> enableFsVerity(int fd) {
     struct fsverity_enable_arg arg = {.version = 1};
 
-    arg.sig_ptr = reinterpret_cast<uint64_t>(pkcs7.data());
-    arg.sig_size = pkcs7.size();
     arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
     arg.block_size = 4096;
 
@@ -197,29 +159,13 @@
     return {};
 }
 
-Result<std::string> enableFsVerity(int fd, const SigningKey& key) {
-    auto digest = createDigest(fd);
-    if (!digest.ok()) {
-        return Error() << digest.error();
+Result<void> enableFsVerity(const std::string& path) {
+    unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
+    if (!fd.ok()) {
+        return Error() << "Can't open " << path;
     }
 
-    auto signed_digest = signDigest(key, digest.value());
-    if (!signed_digest.ok()) {
-        return signed_digest.error();
-    }
-
-    auto pkcs7_data = createPkcs7(signed_digest.value(), kRootSubject);
-    if (!pkcs7_data.ok()) {
-        return pkcs7_data.error();
-    }
-
-    auto enabled = enableFsVerity(fd, pkcs7_data.value());
-    if (!enabled.ok()) {
-        return Error() << enabled.error();
-    }
-
-    // Return the root hash as a hex string
-    return toHex(digest.value());
+    return enableFsVerity(fd.get());
 }
 
 static Result<bool> isFileInVerity(int fd) {
@@ -230,8 +176,7 @@
     return (flags & FS_VERITY_FL) != 0;
 }
 
-Result<std::map<std::string, std::string>> addFilesToVerityRecursive(const std::string& path,
-                                                                     const SigningKey& key) {
+Result<std::map<std::string, std::string>> addFilesToVerityRecursive(const std::string& path) {
     std::map<std::string, std::string> digests;
 
     std::error_code ec;
@@ -245,7 +190,7 @@
             auto enabled = OR_RETURN(isFileInVerity(fd));
             if (!enabled) {
                 LOG(INFO) << "Adding " << it->path() << " to fs-verity...";
-                OR_RETURN(enableFsVerity(fd, key));
+                OR_RETURN(enableFsVerity(fd));
             } else {
                 LOG(INFO) << it->path() << " was already in fs-verity.";
             }
@@ -260,23 +205,6 @@
     return digests;
 }
 
-Result<void> enableFsVerity(const std::string& path, const std::string& signature_path) {
-    unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
-    if (!fd.ok()) {
-        return Error() << "Can't open " << path;
-    }
-
-    std::string signature;
-    android::base::ReadFileToString(signature_path, &signature);
-    std::vector<uint8_t> span = std::vector<uint8_t>(signature.begin(), signature.end());
-
-    const auto& enable = enableFsVerity(fd.get(), span);
-    if (!enable.ok()) {
-        return enable.error();
-    }
-    return {};
-}
-
 Result<std::map<std::string, std::string>> verifyAllFilesInVerity(const std::string& path) {
     std::map<std::string, std::string> digests;
     std::error_code ec;
@@ -306,8 +234,7 @@
 }
 
 Result<void> verifyAllFilesUsingCompOs(const std::string& directory_path,
-                                       const std::map<std::string, std::string>& digests,
-                                       const SigningKey& signing_key) {
+                                       const std::map<std::string, std::string>& digests) {
     std::error_code ec;
     size_t verified_count = 0;
     auto it = std::filesystem::recursive_directory_iterator(directory_path, ec);
@@ -325,41 +252,18 @@
                 return ErrnoError() << "Can't open " << path;
             }
 
-            auto verity_digest = measureFsVerity(fd);
-            if (verity_digest.ok()) {
-                // The file is already in fs-verity. We need to make sure it was signed
-                // by CompOS, so we just check that it has the digest we expect.
-                if (verity_digest.value() == compos_digest) {
-                    ++verified_count;
-                } else {
-                    return Error() << "fs-verity digest does not match CompOS digest: " << path;
-                }
-            } else {
-                // Not in fs-verity yet. We know the digest CompOS provided; If
-                // it's not the correct digest for the file then enabling
-                // fs-verity will fail, so we don't need to check it explicitly
-                // ourselves. Otherwise we should be good.
-                LOG(INFO) << "Adding " << path << " to fs-verity...";
+            bool enabled = OR_RETURN(isFileInVerity(fd));
+            if (!enabled) {
+                LOG(INFO) << "Enabling fs-verity for " << path;
+                OR_RETURN(enableFsVerity(fd));
+            }
 
-                auto digest_bytes = fromHex(compos_digest);
-                if (digest_bytes.empty()) {
-                    return Error() << "Invalid digest " << compos_digest;
-                }
-                auto signed_digest = signDigest(signing_key, digest_bytes);
-                if (!signed_digest.ok()) {
-                    return signed_digest.error();
-                }
-
-                auto pkcs7_data = createPkcs7(signed_digest.value(), kRootSubject);
-                if (!pkcs7_data.ok()) {
-                    return pkcs7_data.error();
-                }
-
-                auto enabled = enableFsVerity(fd, pkcs7_data.value());
-                if (!enabled.ok()) {
-                    return Error() << enabled.error();
-                }
+            auto actual_digest = OR_RETURN(measureFsVerity(fd));
+            // Make sure the file's fs-verity digest matches the known value.
+            if (actual_digest == compos_digest) {
                 ++verified_count;
+            } else {
+                return Error() << "fs-verity digest does not match CompOS digest: " << path;
             }
         } else if (it->is_directory()) {
             // These are fine to ignore
diff --git a/ondevice-signing/include/VerityUtils.h b/ondevice-signing/include/VerityUtils.h
index e6e49c7..626bbdb 100644
--- a/ondevice-signing/include/VerityUtils.h
+++ b/ondevice-signing/include/VerityUtils.h
@@ -22,11 +22,9 @@
 #include <string>
 #include <vector>
 
-#include "SigningKey.h"
-
 android::base::Result<void> addCertToFsVerityKeyring(const std::string& path, const char* keyName);
 android::base::Result<std::vector<uint8_t>> createDigest(const std::string& path);
-android::base::Result<std::string> enableFsVerity(int fd, const SigningKey& key);
+android::base::Result<std::string> enableFsVerity(int fd);
 bool SupportsFsVerity();
 android::base::Result<std::map<std::string, std::string>>
 verifyAllFilesInVerity(const std::string& path);
@@ -34,13 +32,11 @@
 // Note that this function will skip files that are already in fs-verity, and
 // for those files it will return the existing digest.
 android::base::Result<std::map<std::string, std::string>>
-addFilesToVerityRecursive(const std::string& path, const SigningKey& key);
+addFilesToVerityRecursive(const std::string& path);
 
 // Enable verity on the provided file, using the given PKCS7 signature.
-android::base::Result<void> enableFsVerity(const std::string& path,
-                                           const std::string& signature_path);
+android::base::Result<void> enableFsVerity(const std::string& path);
 
 android::base::Result<void>
 verifyAllFilesUsingCompOs(const std::string& directory_path,
-                          const std::map<std::string, std::string>& digests,
-                          const SigningKey& signing_key);
+                          const std::map<std::string, std::string>& digests);
diff --git a/ondevice-signing/odsign_main.cpp b/ondevice-signing/odsign_main.cpp
index 93ec3e4..a688ead 100644
--- a/ondevice-signing/odsign_main.cpp
+++ b/ondevice-signing/odsign_main.cpp
@@ -421,7 +421,7 @@
         std::map<std::string, std::string> compos_digests(compos_info->file_hashes().begin(),
                                                           compos_info->file_hashes().end());
 
-        auto status = verifyAllFilesUsingCompOs(kArtArtifactsDir, compos_digests, signing_key);
+        auto status = verifyAllFilesUsingCompOs(kArtArtifactsDir, compos_digests);
         if (!status.ok()) {
             LOG(WARNING) << "Faild to verify CompOS artifacts: " << status.error();
         } else {
@@ -529,14 +529,6 @@
         } else {
             LOG(INFO) << "Found and verified existing public key certificate: " << kSigningKeyCert;
         }
-        auto cert_add_result = addCertToFsVerityKeyring(kSigningKeyCert, "fsv_ods");
-        if (!cert_add_result.ok()) {
-            LOG(ERROR) << "Failed to add certificate to fs-verity keyring: "
-                       << cert_add_result.error();
-            odsign_record->status =
-                art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_CERT_FAILED;
-            return -1;
-        }
     }
 
     bool digests_verified = false;
@@ -608,7 +600,7 @@
                          : art::metrics::statsd::ODSIGN_REPORTED__STATUS__STATUS_PARTIAL_OK;
         Result<std::map<std::string, std::string>> digests;
         if (supportsFsVerity) {
-            digests = addFilesToVerityRecursive(kArtArtifactsDir, *key);
+            digests = addFilesToVerityRecursive(kArtArtifactsDir);
         } else {
             // If we can't use verity, just compute the root hashes and store
             // those, so we can reverify them at the next boot.
diff --git a/prng_seeder/Android.bp b/prng_seeder/Android.bp
index 5759731..292535a 100644
--- a/prng_seeder/Android.bp
+++ b/prng_seeder/Android.bp
@@ -31,10 +31,9 @@
     ],
 }
 
-rust_binary {
-    name: "prng_seeder",
+rust_defaults {
+    name: "prng_seeder_defaults",
     edition: "2021",
-    srcs: ["src/main.rs"],
     rustlibs: [
         "libanyhow",
         "libbssl_ffi",
@@ -48,3 +47,19 @@
 
     init_rc: ["prng_seeder.rc"],
 }
+
+rust_binary {
+    name: "prng_seeder",
+    defaults: ["prng_seeder_defaults"],
+    srcs: ["src/main.rs"],
+}
+
+rust_binary {
+    name: "prng_seeder_microdroid",
+    defaults: ["prng_seeder_defaults"],
+    srcs: ["src/main.rs"],
+    stem: "prng_seeder",
+    bootstrap: true,
+    installable: false,
+    prefer_rlib: true,
+}