Merge "Add new SecurityLevel::KEYSTORE"
diff --git a/identity/Android.bp b/identity/Android.bp
index dd61930..e6d77c8 100644
--- a/identity/Android.bp
+++ b/identity/Android.bp
@@ -39,8 +39,8 @@
         "libkeystore-attestation-application-id",
     ],
     static_libs: [
-        "android.hardware.identity-unstable-cpp",
-        "android.hardware.keymaster-unstable-cpp",
+        "android.hardware.identity-V3-cpp",
+        "android.hardware.keymaster-V3-cpp",
         "libcppbor",
     ]
 }
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index 785847d..4e12c64 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -617,6 +617,11 @@
         perboot_path_str.push_str(&perboot_path.to_string_lossy());
 
         let conn = Self::make_connection(&persistent_path_str, &perboot_path_str)?;
+        conn.busy_handler(Some(|_| {
+            std::thread::sleep(std::time::Duration::from_micros(50));
+            true
+        }))
+        .context("In KeystoreDB::new: Failed to set busy handler.")?;
 
         Self::init_tables(&conn)?;
         Ok(Self { conn })
diff --git a/keystore2/src/km_compat/Android.bp b/keystore2/src/km_compat/Android.bp
index 126aeff..2180935 100644
--- a/keystore2/src/km_compat/Android.bp
+++ b/keystore2/src/km_compat/Android.bp
@@ -48,11 +48,11 @@
         "android.hardware.keymaster@3.0",
         "android.hardware.keymaster@4.0",
         "android.hardware.keymaster@4.1",
-        "android.hardware.security.keymint-unstable-ndk_platform",
-        "android.hardware.security.secureclock-unstable-ndk_platform",
-        "android.hardware.security.sharedsecret-unstable-ndk_platform",
+        "android.hardware.security.keymint-V1-ndk_platform",
+        "android.hardware.security.secureclock-V1-ndk_platform",
+        "android.hardware.security.sharedsecret-V1-ndk_platform",
         "android.security.compat-ndk_platform",
-        "android.system.keystore2-ndk_platform",
+        "android.system.keystore2-V1-ndk_platform",
         "libbase",
         "libbinder_ndk",
         "libcrypto",
@@ -68,9 +68,9 @@
     name: "libkm_compat_service",
     srcs: ["km_compat_service.cpp"],
     shared_libs: [
-        "android.hardware.security.keymint-unstable-ndk_platform",
-        "android.hardware.security.secureclock-unstable-ndk_platform",
-        "android.hardware.security.sharedsecret-unstable-ndk_platform",
+        "android.hardware.security.keymint-V1-ndk_platform",
+        "android.hardware.security.secureclock-V1-ndk_platform",
+        "android.hardware.security.sharedsecret-V1-ndk_platform",
         "android.security.compat-ndk_platform",
         "libbinder_ndk",
         "libcrypto",
@@ -97,11 +97,11 @@
         "android.hardware.keymaster@3.0",
         "android.hardware.keymaster@4.0",
         "android.hardware.keymaster@4.1",
-        "android.hardware.security.keymint-unstable-ndk_platform",
-        "android.hardware.security.secureclock-unstable-ndk_platform",
-        "android.hardware.security.sharedsecret-unstable-ndk_platform",
+        "android.hardware.security.keymint-V1-ndk_platform",
+        "android.hardware.security.secureclock-V1-ndk_platform",
+        "android.hardware.security.sharedsecret-V1-ndk_platform",
         "android.security.compat-ndk_platform",
-        "android.system.keystore2-ndk_platform",
+        "android.system.keystore2-V1-ndk_platform",
         "libbase",
         "libbinder_ndk",
         "libcrypto",
diff --git a/keystore2/src/km_compat/km_compat.cpp b/keystore2/src/km_compat/km_compat.cpp
index 9383c09..601baf1 100644
--- a/keystore2/src/km_compat/km_compat.cpp
+++ b/keystore2/src/km_compat/km_compat.cpp
@@ -52,19 +52,23 @@
 
 // Utility functions
 
-// Converts a V4 error code into a ScopedAStatus
-ScopedAStatus convertErrorCode(V4_0_ErrorCode result) {
-    if (result == V4_0_ErrorCode::OK) {
+ScopedAStatus convertErrorCode(KMV1::ErrorCode result) {
+    if (result == KMV1::ErrorCode::OK) {
         return ScopedAStatus::ok();
     }
     return ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(result));
 }
 
-static V4_0_ErrorCode toErrorCode(const ScopedAStatus& status) {
+// Converts a V4 error code into a ScopedAStatus
+ScopedAStatus convertErrorCode(V4_0_ErrorCode result) {
+    return convertErrorCode(convert(result));
+}
+
+static KMV1::ErrorCode toErrorCode(const ScopedAStatus& status) {
     if (status.getExceptionCode() == EX_SERVICE_SPECIFIC) {
-        return static_cast<V4_0_ErrorCode>(status.getServiceSpecificError());
+        return static_cast<KMV1::ErrorCode>(status.getServiceSpecificError());
     } else {
-        return V4_0_ErrorCode::UNKNOWN_ERROR;
+        return KMV1::ErrorCode::UNKNOWN_ERROR;
     }
 }
 
@@ -183,25 +187,27 @@
         _aidl_return->keyMintAuthorName = keymasterAuthorName;
     });
     if (!result.isOk()) {
-        return ScopedAStatus::fromServiceSpecificError(
-            static_cast<int32_t>(ResponseCode::SYSTEM_ERROR));
+        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
     }
     return ScopedAStatus::ok();
 }
 
 ScopedAStatus KeyMintDevice::addRngEntropy(const std::vector<uint8_t>& in_data) {
-    V4_0_ErrorCode errorCode = mDevice->addRngEntropy(in_data);
-    return convertErrorCode(errorCode);
+    auto result = mDevice->addRngEntropy(in_data);
+    if (!result.isOk()) {
+        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
+    }
+    return convertErrorCode(result);
 }
 
 ScopedAStatus KeyMintDevice::generateKey(const std::vector<KeyParameter>& in_keyParams,
                                          KeyCreationResult* out_creationResult) {
     auto legacyKeyParams = convertKeyParametersToLegacy(in_keyParams);
-    V4_0_ErrorCode errorCode;
+    KMV1::ErrorCode errorCode;
     auto result = mDevice->generateKey(
         legacyKeyParams, [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
                              const V4_0_KeyCharacteristics& keyCharacteristics) {
-            errorCode = error;
+            errorCode = convert(error);
             out_creationResult->keyBlob = keyBlob;
             out_creationResult->keyCharacteristics =
                 convertKeyCharacteristicsFromLegacy(securityLevel_, keyCharacteristics);
@@ -210,12 +216,12 @@
         return ScopedAStatus::fromServiceSpecificError(
             static_cast<int32_t>(ResponseCode::SYSTEM_ERROR));
     }
-    if (errorCode == V4_0_ErrorCode::OK) {
+    if (errorCode == KMV1::ErrorCode::OK) {
         auto cert = getCertificate(in_keyParams, out_creationResult->keyBlob);
-        if (std::holds_alternative<V4_0_ErrorCode>(cert)) {
-            auto code = std::get<V4_0_ErrorCode>(cert);
+        if (std::holds_alternative<KMV1::ErrorCode>(cert)) {
+            auto code = std::get<KMV1::ErrorCode>(cert);
             // We return OK in successful cases that do not generate a certificate.
-            if (code != V4_0_ErrorCode::OK) {
+            if (code != KMV1::ErrorCode::OK) {
                 errorCode = code;
                 deleteKey(out_creationResult->keyBlob);
             }
@@ -232,26 +238,25 @@
                                        KeyCreationResult* out_creationResult) {
     auto legacyKeyParams = convertKeyParametersToLegacy(in_inKeyParams);
     auto legacyKeyFormat = convertKeyFormatToLegacy(in_inKeyFormat);
-    V4_0_ErrorCode errorCode;
+    KMV1::ErrorCode errorCode;
     auto result = mDevice->importKey(legacyKeyParams, legacyKeyFormat, in_inKeyData,
                                      [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
                                          const V4_0_KeyCharacteristics& keyCharacteristics) {
-                                         errorCode = error;
+                                         errorCode = convert(error);
                                          out_creationResult->keyBlob = keyBlob;
                                          out_creationResult->keyCharacteristics =
                                              convertKeyCharacteristicsFromLegacy(
                                                  securityLevel_, keyCharacteristics);
                                      });
     if (!result.isOk()) {
-        return ScopedAStatus::fromServiceSpecificError(
-            static_cast<int32_t>(ResponseCode::SYSTEM_ERROR));
+        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
     }
-    if (errorCode == V4_0_ErrorCode::OK) {
+    if (errorCode == KMV1::ErrorCode::OK) {
         auto cert = getCertificate(in_inKeyParams, out_creationResult->keyBlob);
-        if (std::holds_alternative<V4_0_ErrorCode>(cert)) {
-            auto code = std::get<V4_0_ErrorCode>(cert);
+        if (std::holds_alternative<KMV1::ErrorCode>(cert)) {
+            auto code = std::get<KMV1::ErrorCode>(cert);
             // We return OK in successful cases that do not generate a certificate.
-            if (code != V4_0_ErrorCode::OK) {
+            if (code != KMV1::ErrorCode::OK) {
                 errorCode = code;
                 deleteKey(out_creationResult->keyBlob);
             }
@@ -268,20 +273,19 @@
     const std::vector<KeyParameter>& in_inUnwrappingParams, int64_t in_inPasswordSid,
     int64_t in_inBiometricSid, KeyCreationResult* out_creationResult) {
     auto legacyUnwrappingParams = convertKeyParametersToLegacy(in_inUnwrappingParams);
-    V4_0_ErrorCode errorCode;
+    KMV1::ErrorCode errorCode;
     auto result = mDevice->importWrappedKey(
         in_inWrappedKeyData, in_inWrappingKeyBlob, in_inMaskingKey, legacyUnwrappingParams,
         in_inPasswordSid, in_inBiometricSid,
         [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
             const V4_0_KeyCharacteristics& keyCharacteristics) {
-            errorCode = error;
+            errorCode = convert(error);
             out_creationResult->keyBlob = keyBlob;
             out_creationResult->keyCharacteristics =
                 convertKeyCharacteristicsFromLegacy(securityLevel_, keyCharacteristics);
         });
     if (!result.isOk()) {
-        return ScopedAStatus::fromServiceSpecificError(
-            static_cast<int32_t>(ResponseCode::SYSTEM_ERROR));
+        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
     }
     return convertErrorCode(errorCode);
 }
@@ -298,20 +302,25 @@
                                 *_aidl_return = upgradedKeyBlob;
                             });
     if (!result.isOk()) {
-        return ScopedAStatus::fromServiceSpecificError(
-            static_cast<int32_t>(ResponseCode::SYSTEM_ERROR));
+        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
     }
     return convertErrorCode(errorCode);
 }
 
 ScopedAStatus KeyMintDevice::deleteKey(const std::vector<uint8_t>& in_inKeyBlob) {
-    V4_0_ErrorCode errorCode = mDevice->deleteKey(in_inKeyBlob);
-    return convertErrorCode(errorCode);
+    auto result = mDevice->deleteKey(in_inKeyBlob);
+    if (!result.isOk()) {
+        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
+    }
+    return convertErrorCode(result);
 }
 
 ScopedAStatus KeyMintDevice::deleteAllKeys() {
-    V4_0_ErrorCode errorCode = mDevice->deleteAllKeys();
-    return convertErrorCode(errorCode);
+    auto result = mDevice->deleteAllKeys();
+    if (!result.isOk()) {
+        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
+    }
+    return convertErrorCode(result);
 }
 
 // We're not implementing this.
@@ -332,24 +341,21 @@
         static_cast<::android::hardware::keymaster::V4_0::KeyPurpose>(in_inPurpose);
     auto legacyParams = convertKeyParametersToLegacy(in_inParams);
     auto legacyAuthToken = convertAuthTokenToLegacy(in_inAuthToken);
-    V4_0_ErrorCode errorCode;
+    KMV1::ErrorCode errorCode;
     auto result = mDevice->begin(
         legacyPurpose, in_inKeyBlob, legacyParams, legacyAuthToken,
         [&](V4_0_ErrorCode error, const hidl_vec<V4_0_KeyParameter>& outParams,
             uint64_t operationHandle) {
-            errorCode = error;
-            _aidl_return->challenge = operationHandle;  // TODO: Is this right?
+            errorCode = convert(error);
+            _aidl_return->challenge = operationHandle;
             _aidl_return->params = convertKeyParametersFromLegacy(outParams);
             _aidl_return->operation = ndk::SharedRefBase::make<KeyMintOperation>(
                 mDevice, operationHandle, &mOperationSlots, error == V4_0_ErrorCode::OK);
         });
     if (!result.isOk()) {
-        // TODO: In this case we're guaranteed that _aidl_return was not initialized, right?
-        mOperationSlots.freeSlot();
-        return ScopedAStatus::fromServiceSpecificError(
-            static_cast<int32_t>(ResponseCode::SYSTEM_ERROR));
+        errorCode = KMV1::ErrorCode::UNKNOWN_ERROR;
     }
-    if (errorCode != V4_0_ErrorCode::OK) {
+    if (errorCode != KMV1::ErrorCode::OK) {
         mOperationSlots.freeSlot();
     }
     return convertErrorCode(errorCode);
@@ -375,12 +381,12 @@
     if (in_inTimeStampToken.has_value()) {
         verificationToken = convertTimestampTokenToLegacy(in_inTimeStampToken.value());
     }
-    V4_0_ErrorCode errorCode;
+    KMV1::ErrorCode errorCode;
     auto result = mDevice->update(
         mOperationHandle, legacyParams, input, authToken, verificationToken,
         [&](V4_0_ErrorCode error, uint32_t inputConsumed,
             const hidl_vec<V4_0_KeyParameter>& outParams, const hidl_vec<uint8_t>& output) {
-            errorCode = error;
+            errorCode = convert(error);
             out_outParams->emplace();
             out_outParams->value().params = convertKeyParametersFromLegacy(outParams);
             out_output->emplace();
@@ -388,11 +394,9 @@
             *_aidl_return = inputConsumed;
         });
     if (!result.isOk()) {
-        mOperationSlot.freeSlot();
-        return ScopedAStatus::fromServiceSpecificError(
-            static_cast<int32_t>(ResponseCode::SYSTEM_ERROR));
+        errorCode = KMV1::ErrorCode::UNKNOWN_ERROR;
     }
-    if (errorCode != V4_0_ErrorCode::OK) {
+    if (errorCode != KMV1::ErrorCode::OK) {
         mOperationSlot.freeSlot();
     }
     return convertErrorCode(errorCode);
@@ -405,7 +409,7 @@
                                        const std::optional<TimeStampToken>& in_inTimeStampToken,
                                        std::optional<KeyParameterArray>* out_outParams,
                                        std::vector<uint8_t>* _aidl_return) {
-    V4_0_ErrorCode errorCode;
+    KMV1::ErrorCode errorCode;
     std::vector<V4_0_KeyParameter> legacyParams;
     if (in_inParams.has_value()) {
         legacyParams = convertKeyParametersToLegacy(in_inParams.value().params);
@@ -424,23 +428,25 @@
         mOperationHandle, legacyParams, input, signature, authToken, verificationToken,
         [&](V4_0_ErrorCode error, const hidl_vec<V4_0_KeyParameter>& outParams,
             const hidl_vec<uint8_t>& output) {
-            errorCode = error;
+            errorCode = convert(error);
             out_outParams->emplace();
             out_outParams->value().params = convertKeyParametersFromLegacy(outParams);
             *_aidl_return = output;
         });
     mOperationSlot.freeSlot();
     if (!result.isOk()) {
-        return ScopedAStatus::fromServiceSpecificError(
-            static_cast<int32_t>(ResponseCode::SYSTEM_ERROR));
+        errorCode = KMV1::ErrorCode::UNKNOWN_ERROR;
     }
     return convertErrorCode(errorCode);
 }
 
 ScopedAStatus KeyMintOperation::abort() {
-    V4_0_ErrorCode errorCode = mDevice->abort(mOperationHandle);
+    auto result = mDevice->abort(mOperationHandle);
     mOperationSlot.freeSlot();
-    return convertErrorCode(errorCode);
+    if (!result.isOk()) {
+        return convertErrorCode(KMV1::ErrorCode::UNKNOWN_ERROR);
+    }
+    return convertErrorCode(result);
 }
 
 KeyMintOperation::~KeyMintOperation() {
@@ -455,18 +461,17 @@
 // SecureClock implementation
 
 ScopedAStatus SecureClock::generateTimeStamp(int64_t in_challenge, TimeStampToken* _aidl_return) {
-    V4_0_ErrorCode errorCode;
+    KMV1::ErrorCode errorCode;
     auto result = mDevice->verifyAuthorization(
         in_challenge, {}, V4_0_HardwareAuthToken(),
         [&](V4_0_ErrorCode error, const V4_0_VerificationToken& token) {
-            errorCode = error;
+            errorCode = convert(error);
             _aidl_return->challenge = token.challenge;
             _aidl_return->timestamp.milliSeconds = token.timestamp;
             _aidl_return->mac = token.mac;
         });
     if (!result.isOk()) {
-        return ScopedAStatus::fromServiceSpecificError(
-            static_cast<int32_t>(ResponseCode::SYSTEM_ERROR));
+        errorCode = KMV1::ErrorCode::UNKNOWN_ERROR;
     }
     return convertErrorCode(errorCode);
 }
@@ -474,17 +479,16 @@
 // SharedSecret implementation
 
 ScopedAStatus SharedSecret::getSharedSecretParameters(SharedSecretParameters* _aidl_return) {
-    V4_0_ErrorCode errorCode;
+    KMV1::ErrorCode errorCode;
     auto result = mDevice->getHmacSharingParameters(
         [&](V4_0_ErrorCode error, const V4_0_HmacSharingParameters& params) {
-            errorCode = error;
+            errorCode = convert(error);
             _aidl_return->seed = params.seed;
             std::copy(params.nonce.data(), params.nonce.data() + params.nonce.elementCount(),
                       std::back_inserter(_aidl_return->nonce));
         });
     if (!result.isOk()) {
-        return ScopedAStatus::fromServiceSpecificError(
-            static_cast<int32_t>(ResponseCode::SYSTEM_ERROR));
+        errorCode = KMV1::ErrorCode::UNKNOWN_ERROR;
     }
     return convertErrorCode(errorCode);
 }
@@ -492,16 +496,15 @@
 ScopedAStatus
 SharedSecret::computeSharedSecret(const std::vector<SharedSecretParameters>& in_params,
                                   std::vector<uint8_t>* _aidl_return) {
-    V4_0_ErrorCode errorCode;
+    KMV1::ErrorCode errorCode;
     auto legacyParams = convertSharedSecretParametersToLegacy(in_params);
     auto result = mDevice->computeSharedHmac(
         legacyParams, [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& sharingCheck) {
-            errorCode = error;
+            errorCode = convert(error);
             *_aidl_return = sharingCheck;
         });
     if (!result.isOk()) {
-        return ScopedAStatus::fromServiceSpecificError(
-            static_cast<int32_t>(ResponseCode::SYSTEM_ERROR));
+        errorCode = KMV1::ErrorCode::UNKNOWN_ERROR;
     }
     return convertErrorCode(errorCode);
 }
@@ -545,12 +548,12 @@
     return *bestSoFar;
 }
 
-static std::variant<keystore::X509_Ptr, V4_0_ErrorCode>
+static std::variant<keystore::X509_Ptr, KMV1::ErrorCode>
 makeCert(::android::sp<Keymaster> mDevice, const std::vector<KeyParameter>& keyParams,
          const std::vector<uint8_t>& keyBlob) {
     // Start generating the certificate.
     // Get public key for makeCert.
-    V4_0_ErrorCode errorCode;
+    KMV1::ErrorCode errorCode;
     std::vector<uint8_t> key;
     static std::vector<uint8_t> empty_vector;
     auto unwrapBlob = [&](auto b) -> const std::vector<uint8_t>& {
@@ -563,13 +566,13 @@
         V4_0_KeyFormat::X509, keyBlob, unwrapBlob(getParam(keyParams, KMV1::TAG_APPLICATION_ID)),
         unwrapBlob(getParam(keyParams, KMV1::TAG_APPLICATION_DATA)),
         [&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& keyMaterial) {
-            errorCode = error;
+            errorCode = convert(error);
             key = keyMaterial;
         });
     if (!result.isOk()) {
-        return V4_0_ErrorCode::UNKNOWN_ERROR;
+        return KMV1::ErrorCode::UNKNOWN_ERROR;
     }
-    if (errorCode != V4_0_ErrorCode::OK) {
+    if (errorCode != KMV1::ErrorCode::OK) {
         return errorCode;
     }
     // Get pkey for makeCert.
@@ -594,12 +597,12 @@
         std::nullopt /* intentionally left blank */, std::nullopt /* intentionally left blank */);
     if (std::holds_alternative<keystore::CertUtilsError>(certOrError)) {
         LOG(ERROR) << __func__ << ": Failed to make certificate";
-        return V4_0_ErrorCode::UNKNOWN_ERROR;
+        return KMV1::ErrorCode::UNKNOWN_ERROR;
     }
     return std::move(std::get<keystore::X509_Ptr>(certOrError));
 }
 
-static std::variant<keystore::Algo, V4_0_ErrorCode> getKeystoreAlgorithm(Algorithm algorithm) {
+static std::variant<keystore::Algo, KMV1::ErrorCode> getKeystoreAlgorithm(Algorithm algorithm) {
     switch (algorithm) {
     case Algorithm::RSA:
         return keystore::Algo::RSA;
@@ -607,11 +610,11 @@
         return keystore::Algo::ECDSA;
     default:
         LOG(ERROR) << __func__ << ": This should not be called with symmetric algorithm.";
-        return V4_0_ErrorCode::UNKNOWN_ERROR;
+        return KMV1::ErrorCode::UNKNOWN_ERROR;
     }
 }
 
-static std::variant<keystore::Padding, V4_0_ErrorCode> getKeystorePadding(PaddingMode padding) {
+static std::variant<keystore::Padding, KMV1::ErrorCode> getKeystorePadding(PaddingMode padding) {
     switch (padding) {
     case PaddingMode::RSA_PKCS1_1_5_SIGN:
         return keystore::Padding::PKCS1_5;
@@ -622,7 +625,7 @@
     }
 }
 
-static std::variant<keystore::Digest, V4_0_ErrorCode> getKeystoreDigest(Digest digest) {
+static std::variant<keystore::Digest, KMV1::ErrorCode> getKeystoreDigest(Digest digest) {
     switch (digest) {
     case Digest::SHA1:
         return keystore::Digest::SHA1;
@@ -637,36 +640,36 @@
         return keystore::Digest::SHA512;
     default:
         LOG(ERROR) << __func__ << ": Unknown digest.";
-        return V4_0_ErrorCode::UNKNOWN_ERROR;
+        return KMV1::ErrorCode::UNKNOWN_ERROR;
     }
 }
 
-std::optional<V4_0_ErrorCode>
+std::optional<KMV1::ErrorCode>
 KeyMintDevice::signCertificate(const std::vector<KeyParameter>& keyParams,
                                const std::vector<uint8_t>& keyBlob, X509* cert) {
     auto algorithm = getParam(keyParams, KMV1::TAG_ALGORITHM);
     auto algoOrError = getKeystoreAlgorithm(*algorithm);
-    if (std::holds_alternative<V4_0_ErrorCode>(algoOrError)) {
-        return std::get<V4_0_ErrorCode>(algoOrError);
+    if (std::holds_alternative<KMV1::ErrorCode>(algoOrError)) {
+        return std::get<KMV1::ErrorCode>(algoOrError);
     }
     auto algo = std::get<keystore::Algo>(algoOrError);
     auto origPadding = getMaximum(keyParams, KMV1::TAG_PADDING,
                                   {PaddingMode::RSA_PSS, PaddingMode::RSA_PKCS1_1_5_SIGN});
     auto paddingOrError = getKeystorePadding(origPadding);
-    if (std::holds_alternative<V4_0_ErrorCode>(paddingOrError)) {
-        return std::get<V4_0_ErrorCode>(paddingOrError);
+    if (std::holds_alternative<KMV1::ErrorCode>(paddingOrError)) {
+        return std::get<KMV1::ErrorCode>(paddingOrError);
     }
     auto padding = std::get<keystore::Padding>(paddingOrError);
     auto origDigest = getMaximum(
         keyParams, KMV1::TAG_DIGEST,
         {Digest::SHA_2_256, Digest::SHA_2_512, Digest::SHA_2_384, Digest::SHA_2_224, Digest::SHA1});
     auto digestOrError = getKeystoreDigest(origDigest);
-    if (std::holds_alternative<V4_0_ErrorCode>(digestOrError)) {
-        return std::get<V4_0_ErrorCode>(digestOrError);
+    if (std::holds_alternative<KMV1::ErrorCode>(digestOrError)) {
+        return std::get<KMV1::ErrorCode>(digestOrError);
     }
     auto digest = std::get<keystore::Digest>(digestOrError);
 
-    V4_0_ErrorCode errorCode = V4_0_ErrorCode::OK;
+    KMV1::ErrorCode errorCode = KMV1::ErrorCode::OK;
     auto error = keystore::signCertWith(
         &*cert,
         [&](const uint8_t* data, size_t len) {
@@ -703,40 +706,40 @@
     if (error) {
         LOG(ERROR) << __func__
                    << ": signCertWith failed. (Callback diagnosed: " << toString(errorCode) << ")";
-        return V4_0_ErrorCode::UNKNOWN_ERROR;
+        return KMV1::ErrorCode::UNKNOWN_ERROR;
     }
-    if (errorCode != V4_0_ErrorCode::OK) {
+    if (errorCode != KMV1::ErrorCode::OK) {
         return errorCode;
     }
     return std::nullopt;
 }
 
-std::variant<std::vector<Certificate>, V4_0_ErrorCode>
+std::variant<std::vector<Certificate>, KMV1::ErrorCode>
 KeyMintDevice::getCertificate(const std::vector<KeyParameter>& keyParams,
                               const std::vector<uint8_t>& keyBlob) {
     // There are no certificates for symmetric keys.
     auto algorithm = getParam(keyParams, KMV1::TAG_ALGORITHM);
     if (!algorithm) {
         LOG(ERROR) << __func__ << ": Unable to determine key algorithm.";
-        return V4_0_ErrorCode::UNKNOWN_ERROR;
+        return KMV1::ErrorCode::UNKNOWN_ERROR;
     }
     switch (*algorithm) {
     case Algorithm::RSA:
     case Algorithm::EC:
         break;
     default:
-        return V4_0_ErrorCode::OK;
+        return KMV1::ErrorCode::OK;
     }
 
     // If attestation was requested, call and use attestKey.
     if (containsParam(keyParams, KMV1::TAG_ATTESTATION_CHALLENGE)) {
         auto legacyParams = convertKeyParametersToLegacy(keyParams);
         std::vector<Certificate> certs;
-        V4_0_ErrorCode errorCode = V4_0_ErrorCode::OK;
+        KMV1::ErrorCode errorCode = KMV1::ErrorCode::OK;
         auto result = mDevice->attestKey(
             keyBlob, legacyParams,
-            [&](V4_0_ErrorCode error, const hidl_vec<hidl_vec<uint8_t>>& certChain) {
-                errorCode = error;
+            [&](V4_0::ErrorCode error, const hidl_vec<hidl_vec<uint8_t>>& certChain) {
+                errorCode = convert(error);
                 for (const auto& cert : certChain) {
                     Certificate certificate;
                     certificate.encodedCertificate = cert;
@@ -745,9 +748,9 @@
             });
         if (!result.isOk()) {
             LOG(ERROR) << __func__ << ": Call to attestKey failed.";
-            return V4_0_ErrorCode::UNKNOWN_ERROR;
+            return KMV1::ErrorCode::UNKNOWN_ERROR;
         }
-        if (errorCode != V4_0_ErrorCode::OK) {
+        if (errorCode != KMV1::ErrorCode::OK) {
             return errorCode;
         }
         return certs;
@@ -755,8 +758,8 @@
 
     // makeCert
     auto certOrError = makeCert(mDevice, keyParams, keyBlob);
-    if (std::holds_alternative<V4_0_ErrorCode>(certOrError)) {
-        return std::get<V4_0_ErrorCode>(certOrError);
+    if (std::holds_alternative<KMV1::ErrorCode>(certOrError)) {
+        return std::get<KMV1::ErrorCode>(certOrError);
     }
     auto cert = std::move(std::get<keystore::X509_Ptr>(certOrError));
 
@@ -764,7 +767,7 @@
     auto error = keystore::setIssuer(&*cert, &*cert, false);
     if (error) {
         LOG(ERROR) << __func__ << ": Set issuer failed.";
-        return V4_0_ErrorCode::UNKNOWN_ERROR;
+        return KMV1::ErrorCode::UNKNOWN_ERROR;
     }
 
     // Signing
@@ -789,7 +792,7 @@
         error = keystore::signCert(&*cert, pkey_ptr);
         if (error) {
             LOG(ERROR) << __func__ << ": signCert failed.";
-            return V4_0_ErrorCode::UNKNOWN_ERROR;
+            return KMV1::ErrorCode::UNKNOWN_ERROR;
         }
     }
 
@@ -797,7 +800,7 @@
     auto encodedCertOrError = keystore::encodeCert(&*cert);
     if (std::holds_alternative<keystore::CertUtilsError>(encodedCertOrError)) {
         LOG(ERROR) << __func__ << ": encodeCert failed.";
-        return V4_0_ErrorCode::UNKNOWN_ERROR;
+        return KMV1::ErrorCode::UNKNOWN_ERROR;
     }
 
     Certificate certificate{.encodedCertificate =
diff --git a/keystore2/src/km_compat/km_compat.h b/keystore2/src/km_compat/km_compat.h
index 481481a..5637b58 100644
--- a/keystore2/src/km_compat/km_compat.h
+++ b/keystore2/src/km_compat/km_compat.h
@@ -18,6 +18,7 @@
 
 #include <aidl/android/hardware/security/keymint/BnKeyMintDevice.h>
 #include <aidl/android/hardware/security/keymint/BnKeyMintOperation.h>
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
 #include <aidl/android/hardware/security/secureclock/BnSecureClock.h>
 #include <aidl/android/hardware/security/sharedsecret/BnSharedSecret.h>
 #include <aidl/android/security/compat/BnKeystoreCompatService.h>
@@ -41,6 +42,7 @@
 using KeyMintSecurityLevel = ::aidl::android::hardware::security::keymint::SecurityLevel;
 using V4_0_ErrorCode = ::android::hardware::keymaster::V4_0::ErrorCode;
 using ::aidl::android::hardware::security::keymint::IKeyMintDevice;
+using KMV1_ErrorCode = ::aidl::android::hardware::security::keymint::ErrorCode;
 using ::aidl::android::hardware::security::secureclock::ISecureClock;
 using ::aidl::android::hardware::security::secureclock::TimeStampToken;
 using ::aidl::android::hardware::security::sharedsecret::ISharedSecret;
@@ -112,13 +114,13 @@
     // These are public to allow testing code to use them directly.
     // This class should not be used publicly anyway.
 
-    std::variant<std::vector<Certificate>, V4_0_ErrorCode>
+    std::variant<std::vector<Certificate>, KMV1_ErrorCode>
     getCertificate(const std::vector<KeyParameter>& keyParams, const std::vector<uint8_t>& keyBlob);
 
     void setNumFreeSlots(uint8_t numFreeSlots);
 
   private:
-    std::optional<V4_0_ErrorCode> signCertificate(const std::vector<KeyParameter>& keyParams,
+    std::optional<KMV1_ErrorCode> signCertificate(const std::vector<KeyParameter>& keyParams,
                                                   const std::vector<uint8_t>& keyBlob, X509* cert);
     KeyMintSecurityLevel securityLevel_;
 };
diff --git a/keystore2/src/km_compat/km_compat_type_conversion.h b/keystore2/src/km_compat/km_compat_type_conversion.h
index c0e872b..5fdca91 100644
--- a/keystore2/src/km_compat/km_compat_type_conversion.h
+++ b/keystore2/src/km_compat/km_compat_type_conversion.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
 #include <keymasterV4_1/keymaster_tags.h>
 #include <keymint_support/keymint_tags.h>
 
@@ -23,6 +24,159 @@
 namespace V4_1 = ::android::hardware::keymaster::V4_1;
 namespace KMV1 = ::aidl::android::hardware::security::keymint;
 
+static KMV1::ErrorCode convert(V4_0::ErrorCode error) {
+    switch (error) {
+    case V4_0::ErrorCode::OK:
+        return KMV1::ErrorCode::OK;
+    case V4_0::ErrorCode::ROOT_OF_TRUST_ALREADY_SET:
+        return KMV1::ErrorCode::ROOT_OF_TRUST_ALREADY_SET;
+    case V4_0::ErrorCode::UNSUPPORTED_PURPOSE:
+        return KMV1::ErrorCode::UNSUPPORTED_PURPOSE;
+    case V4_0::ErrorCode::INCOMPATIBLE_PURPOSE:
+        return KMV1::ErrorCode::INCOMPATIBLE_PURPOSE;
+    case V4_0::ErrorCode::UNSUPPORTED_ALGORITHM:
+        return KMV1::ErrorCode::UNSUPPORTED_ALGORITHM;
+    case V4_0::ErrorCode::INCOMPATIBLE_ALGORITHM:
+        return KMV1::ErrorCode::INCOMPATIBLE_ALGORITHM;
+    case V4_0::ErrorCode::UNSUPPORTED_KEY_SIZE:
+        return KMV1::ErrorCode::UNSUPPORTED_KEY_SIZE;
+    case V4_0::ErrorCode::UNSUPPORTED_BLOCK_MODE:
+        return KMV1::ErrorCode::UNSUPPORTED_BLOCK_MODE;
+    case V4_0::ErrorCode::INCOMPATIBLE_BLOCK_MODE:
+        return KMV1::ErrorCode::INCOMPATIBLE_BLOCK_MODE;
+    case V4_0::ErrorCode::UNSUPPORTED_MAC_LENGTH:
+        return KMV1::ErrorCode::UNSUPPORTED_MAC_LENGTH;
+    case V4_0::ErrorCode::UNSUPPORTED_PADDING_MODE:
+        return KMV1::ErrorCode::UNSUPPORTED_PADDING_MODE;
+    case V4_0::ErrorCode::INCOMPATIBLE_PADDING_MODE:
+        return KMV1::ErrorCode::INCOMPATIBLE_PADDING_MODE;
+    case V4_0::ErrorCode::UNSUPPORTED_DIGEST:
+        return KMV1::ErrorCode::UNSUPPORTED_DIGEST;
+    case V4_0::ErrorCode::INCOMPATIBLE_DIGEST:
+        return KMV1::ErrorCode::INCOMPATIBLE_DIGEST;
+    case V4_0::ErrorCode::INVALID_EXPIRATION_TIME:
+        return KMV1::ErrorCode::INVALID_EXPIRATION_TIME;
+    case V4_0::ErrorCode::INVALID_USER_ID:
+        return KMV1::ErrorCode::INVALID_USER_ID;
+    case V4_0::ErrorCode::INVALID_AUTHORIZATION_TIMEOUT:
+        return KMV1::ErrorCode::INVALID_AUTHORIZATION_TIMEOUT;
+    case V4_0::ErrorCode::UNSUPPORTED_KEY_FORMAT:
+        return KMV1::ErrorCode::UNSUPPORTED_KEY_FORMAT;
+    case V4_0::ErrorCode::INCOMPATIBLE_KEY_FORMAT:
+        return KMV1::ErrorCode::INCOMPATIBLE_KEY_FORMAT;
+    case V4_0::ErrorCode::UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM:
+        return KMV1::ErrorCode::UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM;
+    case V4_0::ErrorCode::UNSUPPORTED_KEY_VERIFICATION_ALGORITHM:
+        return KMV1::ErrorCode::UNSUPPORTED_KEY_VERIFICATION_ALGORITHM;
+    case V4_0::ErrorCode::INVALID_INPUT_LENGTH:
+        return KMV1::ErrorCode::INVALID_INPUT_LENGTH;
+    case V4_0::ErrorCode::KEY_EXPORT_OPTIONS_INVALID:
+        return KMV1::ErrorCode::KEY_EXPORT_OPTIONS_INVALID;
+    case V4_0::ErrorCode::DELEGATION_NOT_ALLOWED:
+        return KMV1::ErrorCode::DELEGATION_NOT_ALLOWED;
+    case V4_0::ErrorCode::KEY_NOT_YET_VALID:
+        return KMV1::ErrorCode::KEY_NOT_YET_VALID;
+    case V4_0::ErrorCode::KEY_EXPIRED:
+        return KMV1::ErrorCode::KEY_EXPIRED;
+    case V4_0::ErrorCode::KEY_USER_NOT_AUTHENTICATED:
+        return KMV1::ErrorCode::KEY_USER_NOT_AUTHENTICATED;
+    case V4_0::ErrorCode::OUTPUT_PARAMETER_NULL:
+        return KMV1::ErrorCode::OUTPUT_PARAMETER_NULL;
+    case V4_0::ErrorCode::INVALID_OPERATION_HANDLE:
+        return KMV1::ErrorCode::INVALID_OPERATION_HANDLE;
+    case V4_0::ErrorCode::INSUFFICIENT_BUFFER_SPACE:
+        return KMV1::ErrorCode::INSUFFICIENT_BUFFER_SPACE;
+    case V4_0::ErrorCode::VERIFICATION_FAILED:
+        return KMV1::ErrorCode::VERIFICATION_FAILED;
+    case V4_0::ErrorCode::TOO_MANY_OPERATIONS:
+        return KMV1::ErrorCode::TOO_MANY_OPERATIONS;
+    case V4_0::ErrorCode::UNEXPECTED_NULL_POINTER:
+        return KMV1::ErrorCode::UNEXPECTED_NULL_POINTER;
+    case V4_0::ErrorCode::INVALID_KEY_BLOB:
+        return KMV1::ErrorCode::INVALID_KEY_BLOB;
+    case V4_0::ErrorCode::IMPORTED_KEY_NOT_ENCRYPTED:
+        return KMV1::ErrorCode::IMPORTED_KEY_NOT_ENCRYPTED;
+    case V4_0::ErrorCode::IMPORTED_KEY_DECRYPTION_FAILED:
+        return KMV1::ErrorCode::IMPORTED_KEY_DECRYPTION_FAILED;
+    case V4_0::ErrorCode::IMPORTED_KEY_NOT_SIGNED:
+        return KMV1::ErrorCode::IMPORTED_KEY_NOT_SIGNED;
+    case V4_0::ErrorCode::IMPORTED_KEY_VERIFICATION_FAILED:
+        return KMV1::ErrorCode::IMPORTED_KEY_VERIFICATION_FAILED;
+    case V4_0::ErrorCode::INVALID_ARGUMENT:
+        return KMV1::ErrorCode::INVALID_ARGUMENT;
+    case V4_0::ErrorCode::UNSUPPORTED_TAG:
+        return KMV1::ErrorCode::UNSUPPORTED_TAG;
+    case V4_0::ErrorCode::INVALID_TAG:
+        return KMV1::ErrorCode::INVALID_TAG;
+    case V4_0::ErrorCode::MEMORY_ALLOCATION_FAILED:
+        return KMV1::ErrorCode::MEMORY_ALLOCATION_FAILED;
+    case V4_0::ErrorCode::IMPORT_PARAMETER_MISMATCH:
+        return KMV1::ErrorCode::IMPORT_PARAMETER_MISMATCH;
+    case V4_0::ErrorCode::SECURE_HW_ACCESS_DENIED:
+        return KMV1::ErrorCode::SECURE_HW_ACCESS_DENIED;
+    case V4_0::ErrorCode::OPERATION_CANCELLED:
+        return KMV1::ErrorCode::OPERATION_CANCELLED;
+    case V4_0::ErrorCode::CONCURRENT_ACCESS_CONFLICT:
+        return KMV1::ErrorCode::CONCURRENT_ACCESS_CONFLICT;
+    case V4_0::ErrorCode::SECURE_HW_BUSY:
+        return KMV1::ErrorCode::SECURE_HW_BUSY;
+    case V4_0::ErrorCode::SECURE_HW_COMMUNICATION_FAILED:
+        return KMV1::ErrorCode::SECURE_HW_COMMUNICATION_FAILED;
+    case V4_0::ErrorCode::UNSUPPORTED_EC_FIELD:
+        return KMV1::ErrorCode::UNSUPPORTED_EC_FIELD;
+    case V4_0::ErrorCode::MISSING_NONCE:
+        return KMV1::ErrorCode::MISSING_NONCE;
+    case V4_0::ErrorCode::INVALID_NONCE:
+        return KMV1::ErrorCode::INVALID_NONCE;
+    case V4_0::ErrorCode::MISSING_MAC_LENGTH:
+        return KMV1::ErrorCode::MISSING_MAC_LENGTH;
+    case V4_0::ErrorCode::KEY_RATE_LIMIT_EXCEEDED:
+        return KMV1::ErrorCode::KEY_RATE_LIMIT_EXCEEDED;
+    case V4_0::ErrorCode::CALLER_NONCE_PROHIBITED:
+        return KMV1::ErrorCode::CALLER_NONCE_PROHIBITED;
+    case V4_0::ErrorCode::KEY_MAX_OPS_EXCEEDED:
+        return KMV1::ErrorCode::KEY_MAX_OPS_EXCEEDED;
+    case V4_0::ErrorCode::INVALID_MAC_LENGTH:
+        return KMV1::ErrorCode::INVALID_MAC_LENGTH;
+    case V4_0::ErrorCode::MISSING_MIN_MAC_LENGTH:
+        return KMV1::ErrorCode::MISSING_MIN_MAC_LENGTH;
+    case V4_0::ErrorCode::UNSUPPORTED_MIN_MAC_LENGTH:
+        return KMV1::ErrorCode::UNSUPPORTED_MIN_MAC_LENGTH;
+    case V4_0::ErrorCode::UNSUPPORTED_KDF:
+        return KMV1::ErrorCode::UNSUPPORTED_KDF;
+    case V4_0::ErrorCode::UNSUPPORTED_EC_CURVE:
+        return KMV1::ErrorCode::UNSUPPORTED_EC_CURVE;
+    case V4_0::ErrorCode::KEY_REQUIRES_UPGRADE:
+        return KMV1::ErrorCode::KEY_REQUIRES_UPGRADE;
+    case V4_0::ErrorCode::ATTESTATION_CHALLENGE_MISSING:
+        return KMV1::ErrorCode::ATTESTATION_CHALLENGE_MISSING;
+    case V4_0::ErrorCode::KEYMASTER_NOT_CONFIGURED:
+        return KMV1::ErrorCode::KEYMINT_NOT_CONFIGURED;
+    case V4_0::ErrorCode::ATTESTATION_APPLICATION_ID_MISSING:
+        return KMV1::ErrorCode::ATTESTATION_APPLICATION_ID_MISSING;
+    case V4_0::ErrorCode::CANNOT_ATTEST_IDS:
+        return KMV1::ErrorCode::CANNOT_ATTEST_IDS;
+    case V4_0::ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE:
+        return KMV1::ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE;
+    case V4_0::ErrorCode::HARDWARE_TYPE_UNAVAILABLE:
+        return KMV1::ErrorCode::HARDWARE_TYPE_UNAVAILABLE;
+    case V4_0::ErrorCode::PROOF_OF_PRESENCE_REQUIRED:
+        return KMV1::ErrorCode::PROOF_OF_PRESENCE_REQUIRED;
+    case V4_0::ErrorCode::CONCURRENT_PROOF_OF_PRESENCE_REQUESTED:
+        return KMV1::ErrorCode::CONCURRENT_PROOF_OF_PRESENCE_REQUESTED;
+    case V4_0::ErrorCode::NO_USER_CONFIRMATION:
+        return KMV1::ErrorCode::NO_USER_CONFIRMATION;
+    case V4_0::ErrorCode::DEVICE_LOCKED:
+        return KMV1::ErrorCode::DEVICE_LOCKED;
+    case V4_0::ErrorCode::UNIMPLEMENTED:
+        return KMV1::ErrorCode::UNIMPLEMENTED;
+    case V4_0::ErrorCode::VERSION_MISMATCH:
+        return KMV1::ErrorCode::VERSION_MISMATCH;
+    case V4_0::ErrorCode::UNKNOWN_ERROR:
+        return KMV1::ErrorCode::UNKNOWN_ERROR;
+    }
+}
+
 static std::optional<V4_0::KeyPurpose> convert(KMV1::KeyPurpose p) {
     switch (p) {
     case KMV1::KeyPurpose::ENCRYPT:
diff --git a/keystore2/src/km_compat/lib.rs b/keystore2/src/km_compat/lib.rs
index 7814364..d264e7a 100644
--- a/keystore2/src/km_compat/lib.rs
+++ b/keystore2/src/km_compat/lib.rs
@@ -39,23 +39,32 @@
 
     static COMPAT_NAME: &str = "android.security.compat";
 
-    fn get_device() -> Box<dyn IKeyMintDevice> {
+    fn get_device() -> Option<Box<dyn IKeyMintDevice>> {
         add_keymint_device_service();
         let compat_service: Box<dyn IKeystoreCompatService> =
-            binder::get_interface(COMPAT_NAME).unwrap();
-        compat_service.getKeyMintDevice(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap()
+            binder::get_interface(COMPAT_NAME).ok()?;
+        compat_service.getKeyMintDevice(SecurityLevel::TRUSTED_ENVIRONMENT).ok()
+    }
+
+    macro_rules! get_device_or_skip_test {
+        () => {
+            match get_device() {
+                Some(dev) => dev,
+                None => return,
+            }
+        };
     }
 
     #[test]
     fn test_get_hardware_info() {
-        let legacy = get_device();
+        let legacy = get_device_or_skip_test!();
         let hinfo = legacy.getHardwareInfo();
         assert!(hinfo.is_ok());
     }
 
     #[test]
     fn test_add_rng_entropy() {
-        let legacy = get_device();
+        let legacy = get_device_or_skip_test!();
         let result = legacy.addRngEntropy(&[42; 16]);
         assert!(result.is_ok(), "{:?}", result);
     }
@@ -117,25 +126,25 @@
 
     #[test]
     fn test_generate_key_no_encrypt() {
-        let legacy = get_device();
+        let legacy = get_device_or_skip_test!();
         generate_rsa_key(legacy.as_ref(), false, false);
     }
 
     #[test]
     fn test_generate_key_encrypt() {
-        let legacy = get_device();
+        let legacy = get_device_or_skip_test!();
         generate_rsa_key(legacy.as_ref(), true, false);
     }
 
     #[test]
     fn test_generate_key_attested() {
-        let legacy = get_device();
+        let legacy = get_device_or_skip_test!();
         generate_rsa_key(legacy.as_ref(), false, true);
     }
 
     #[test]
     fn test_import_key() {
-        let legacy = get_device();
+        let legacy = get_device_or_skip_test!();
         let kps = [KeyParameter {
             tag: Tag::ALGORITHM,
             value: KeyParameterValue::Algorithm(Algorithm::AES),
@@ -149,7 +158,7 @@
 
     #[test]
     fn test_import_wrapped_key() {
-        let legacy = get_device();
+        let legacy = get_device_or_skip_test!();
         let result = legacy.importWrappedKey(&[], &[], &[], &[], 0, 0);
         // For this test we only care that there was no crash.
         assert!(result.is_ok() || result.is_err());
@@ -157,7 +166,7 @@
 
     #[test]
     fn test_upgrade_key() {
-        let legacy = get_device();
+        let legacy = get_device_or_skip_test!();
         let blob = generate_rsa_key(legacy.as_ref(), false, false);
         let result = legacy.upgradeKey(&blob, &[]);
         // For this test we only care that there was no crash.
@@ -166,7 +175,7 @@
 
     #[test]
     fn test_delete_key() {
-        let legacy = get_device();
+        let legacy = get_device_or_skip_test!();
         let blob = generate_rsa_key(legacy.as_ref(), false, false);
         let result = legacy.deleteKey(&blob);
         assert!(result.is_ok(), "{:?}", result);
@@ -174,14 +183,14 @@
 
     #[test]
     fn test_delete_all_keys() {
-        let legacy = get_device();
+        let legacy = get_device_or_skip_test!();
         let result = legacy.deleteAllKeys();
         assert!(result.is_ok(), "{:?}", result);
     }
 
     #[test]
     fn test_destroy_attestation_ids() {
-        let legacy = get_device();
+        let legacy = get_device_or_skip_test!();
         let result = legacy.destroyAttestationIds();
         assert!(result.is_err());
         assert_eq!(result.unwrap_err().service_specific_error(), ErrorCode::UNIMPLEMENTED.0,);
@@ -243,7 +252,7 @@
 
     #[test]
     fn test_begin_abort() {
-        let legacy = get_device();
+        let legacy = get_device_or_skip_test!();
         let blob = generate_aes_key(legacy.as_ref());
         let begin_result = begin(legacy.as_ref(), &blob, KeyPurpose::ENCRYPT, None);
         let operation = begin_result.operation.unwrap();
@@ -255,7 +264,7 @@
 
     #[test]
     fn test_begin_update_finish() {
-        let legacy = get_device();
+        let legacy = get_device_or_skip_test!();
         let blob = generate_aes_key(legacy.as_ref());
 
         let begin_result = begin(legacy.as_ref(), &blob, KeyPurpose::ENCRYPT, None);
diff --git a/keystore2/src/km_compat/parameter_conversion_test.cpp b/keystore2/src/km_compat/parameter_conversion_test.cpp
index 41be067..48af20c 100644
--- a/keystore2/src/km_compat/parameter_conversion_test.cpp
+++ b/keystore2/src/km_compat/parameter_conversion_test.cpp
@@ -150,3 +150,84 @@
     TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_USER_SECURE_ID);
     TEST_KEY_PARAMETER_CONVERSION_V4_0(TAG_VENDOR_PATCHLEVEL);
 }
+
+#define TEST_ERROR_CODE_CONVERSION(variant)                                                        \
+    ASSERT_EQ(KMV1::ErrorCode::variant, convert(V4_0::ErrorCode::variant))
+
+TEST(KmCompatTypeConversionTest, testErrorCodeConversion) {
+    TEST_ERROR_CODE_CONVERSION(OK);
+    TEST_ERROR_CODE_CONVERSION(ROOT_OF_TRUST_ALREADY_SET);
+    TEST_ERROR_CODE_CONVERSION(UNSUPPORTED_PURPOSE);
+    TEST_ERROR_CODE_CONVERSION(INCOMPATIBLE_PURPOSE);
+    TEST_ERROR_CODE_CONVERSION(UNSUPPORTED_ALGORITHM);
+    TEST_ERROR_CODE_CONVERSION(INCOMPATIBLE_ALGORITHM);
+    TEST_ERROR_CODE_CONVERSION(UNSUPPORTED_KEY_SIZE);
+    TEST_ERROR_CODE_CONVERSION(UNSUPPORTED_BLOCK_MODE);
+    TEST_ERROR_CODE_CONVERSION(INCOMPATIBLE_BLOCK_MODE);
+    TEST_ERROR_CODE_CONVERSION(UNSUPPORTED_MAC_LENGTH);
+    TEST_ERROR_CODE_CONVERSION(UNSUPPORTED_PADDING_MODE);
+    TEST_ERROR_CODE_CONVERSION(INCOMPATIBLE_PADDING_MODE);
+    TEST_ERROR_CODE_CONVERSION(UNSUPPORTED_DIGEST);
+    TEST_ERROR_CODE_CONVERSION(INCOMPATIBLE_DIGEST);
+    TEST_ERROR_CODE_CONVERSION(INVALID_EXPIRATION_TIME);
+    TEST_ERROR_CODE_CONVERSION(INVALID_USER_ID);
+    TEST_ERROR_CODE_CONVERSION(INVALID_AUTHORIZATION_TIMEOUT);
+    TEST_ERROR_CODE_CONVERSION(UNSUPPORTED_KEY_FORMAT);
+    TEST_ERROR_CODE_CONVERSION(INCOMPATIBLE_KEY_FORMAT);
+    TEST_ERROR_CODE_CONVERSION(UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM);
+    TEST_ERROR_CODE_CONVERSION(UNSUPPORTED_KEY_VERIFICATION_ALGORITHM);
+    TEST_ERROR_CODE_CONVERSION(INVALID_INPUT_LENGTH);
+    TEST_ERROR_CODE_CONVERSION(KEY_EXPORT_OPTIONS_INVALID);
+    TEST_ERROR_CODE_CONVERSION(DELEGATION_NOT_ALLOWED);
+    TEST_ERROR_CODE_CONVERSION(KEY_NOT_YET_VALID);
+    TEST_ERROR_CODE_CONVERSION(KEY_EXPIRED);
+    TEST_ERROR_CODE_CONVERSION(KEY_USER_NOT_AUTHENTICATED);
+    TEST_ERROR_CODE_CONVERSION(OUTPUT_PARAMETER_NULL);
+    TEST_ERROR_CODE_CONVERSION(INVALID_OPERATION_HANDLE);
+    TEST_ERROR_CODE_CONVERSION(INSUFFICIENT_BUFFER_SPACE);
+    TEST_ERROR_CODE_CONVERSION(VERIFICATION_FAILED);
+    TEST_ERROR_CODE_CONVERSION(TOO_MANY_OPERATIONS);
+    TEST_ERROR_CODE_CONVERSION(UNEXPECTED_NULL_POINTER);
+    TEST_ERROR_CODE_CONVERSION(INVALID_KEY_BLOB);
+    TEST_ERROR_CODE_CONVERSION(IMPORTED_KEY_NOT_ENCRYPTED);
+    TEST_ERROR_CODE_CONVERSION(IMPORTED_KEY_DECRYPTION_FAILED);
+    TEST_ERROR_CODE_CONVERSION(IMPORTED_KEY_NOT_SIGNED);
+    TEST_ERROR_CODE_CONVERSION(IMPORTED_KEY_VERIFICATION_FAILED);
+    TEST_ERROR_CODE_CONVERSION(INVALID_ARGUMENT);
+    TEST_ERROR_CODE_CONVERSION(UNSUPPORTED_TAG);
+    TEST_ERROR_CODE_CONVERSION(INVALID_TAG);
+    TEST_ERROR_CODE_CONVERSION(MEMORY_ALLOCATION_FAILED);
+    TEST_ERROR_CODE_CONVERSION(IMPORT_PARAMETER_MISMATCH);
+    TEST_ERROR_CODE_CONVERSION(SECURE_HW_ACCESS_DENIED);
+    TEST_ERROR_CODE_CONVERSION(OPERATION_CANCELLED);
+    TEST_ERROR_CODE_CONVERSION(CONCURRENT_ACCESS_CONFLICT);
+    TEST_ERROR_CODE_CONVERSION(SECURE_HW_BUSY);
+    TEST_ERROR_CODE_CONVERSION(SECURE_HW_COMMUNICATION_FAILED);
+    TEST_ERROR_CODE_CONVERSION(UNSUPPORTED_EC_FIELD);
+    TEST_ERROR_CODE_CONVERSION(MISSING_NONCE);
+    TEST_ERROR_CODE_CONVERSION(INVALID_NONCE);
+    TEST_ERROR_CODE_CONVERSION(MISSING_MAC_LENGTH);
+    TEST_ERROR_CODE_CONVERSION(KEY_RATE_LIMIT_EXCEEDED);
+    TEST_ERROR_CODE_CONVERSION(CALLER_NONCE_PROHIBITED);
+    TEST_ERROR_CODE_CONVERSION(KEY_MAX_OPS_EXCEEDED);
+    TEST_ERROR_CODE_CONVERSION(INVALID_MAC_LENGTH);
+    TEST_ERROR_CODE_CONVERSION(MISSING_MIN_MAC_LENGTH);
+    TEST_ERROR_CODE_CONVERSION(UNSUPPORTED_MIN_MAC_LENGTH);
+    TEST_ERROR_CODE_CONVERSION(UNSUPPORTED_KDF);
+    TEST_ERROR_CODE_CONVERSION(UNSUPPORTED_EC_CURVE);
+    TEST_ERROR_CODE_CONVERSION(KEY_REQUIRES_UPGRADE);
+    TEST_ERROR_CODE_CONVERSION(ATTESTATION_CHALLENGE_MISSING);
+    ASSERT_EQ(KMV1::ErrorCode::KEYMINT_NOT_CONFIGURED,
+              convert(V4_0::ErrorCode::KEYMASTER_NOT_CONFIGURED));
+    TEST_ERROR_CODE_CONVERSION(ATTESTATION_APPLICATION_ID_MISSING);
+    TEST_ERROR_CODE_CONVERSION(CANNOT_ATTEST_IDS);
+    TEST_ERROR_CODE_CONVERSION(ROLLBACK_RESISTANCE_UNAVAILABLE);
+    TEST_ERROR_CODE_CONVERSION(HARDWARE_TYPE_UNAVAILABLE);
+    TEST_ERROR_CODE_CONVERSION(PROOF_OF_PRESENCE_REQUIRED);
+    TEST_ERROR_CODE_CONVERSION(CONCURRENT_PROOF_OF_PRESENCE_REQUESTED);
+    TEST_ERROR_CODE_CONVERSION(NO_USER_CONFIRMATION);
+    TEST_ERROR_CODE_CONVERSION(DEVICE_LOCKED);
+    TEST_ERROR_CODE_CONVERSION(UNIMPLEMENTED);
+    TEST_ERROR_CODE_CONVERSION(VERSION_MISMATCH);
+    TEST_ERROR_CODE_CONVERSION(UNKNOWN_ERROR);
+}
diff --git a/keystore2/src/operation.rs b/keystore2/src/operation.rs
index 829987d..97bab77 100644
--- a/keystore2/src/operation.rs
+++ b/keystore2/src/operation.rs
@@ -368,7 +368,6 @@
         self.touch();
 
         let mut out_params: Option<KeyParameterArray> = None;
-        let mut output: Option<ByteArray> = None;
 
         let km_op: Box<dyn IKeyMintOperation> =
             self.km_op.get_interface().context("In update: Failed to get KeyMintOperation.")?;
@@ -380,28 +379,39 @@
             .before_update()
             .context("In update: Trying to get auth tokens.")?;
 
-        self.update_outcome(
-            &mut *outcome,
-            map_km_error(km_op.update(
-                None,
-                Some(input),
-                hat.as_ref(),
-                tst.as_ref(),
-                &mut out_params,
-                &mut output,
-            )),
-        )
-        .context("In update: KeyMint::update failed.")?;
+        let mut result: Option<Vec<u8>> = None;
+        let mut consumed = 0usize;
+        loop {
+            let mut output: Option<ByteArray> = None;
+            consumed += self
+                .update_outcome(
+                    &mut *outcome,
+                    map_km_error(km_op.update(
+                        None,
+                        Some(&input[consumed..]),
+                        hat.as_ref(),
+                        tst.as_ref(),
+                        &mut out_params,
+                        &mut output,
+                    )),
+                )
+                .context("In update: KeyMint::update failed.")? as usize;
 
-        match output {
-            Some(blob) => {
-                if blob.data.is_empty() {
-                    Ok(None)
-                } else {
-                    Ok(Some(blob.data))
+            match (output, &mut result) {
+                (Some(blob), None) => {
+                    if !blob.data.is_empty() {
+                        result = Some(blob.data)
+                    }
                 }
+                (Some(mut blob), Some(ref mut result)) => {
+                    result.append(&mut blob.data);
+                }
+                (None, _) => {}
             }
-            None => Ok(None),
+
+            if consumed == input.len() {
+                return Ok(result);
+            }
         }
     }
 
diff --git a/keystore2/src/permission.rs b/keystore2/src/permission.rs
index a81954f..0f0ca04 100644
--- a/keystore2/src/permission.rs
+++ b/keystore2/src/permission.rs
@@ -454,9 +454,12 @@
 
     for p in access_vec.into_iter() {
         selinux::check_access(caller_ctx, &target_context, "keystore2_key", p.to_selinux())
-            .context(concat!(
-                "check_grant_permission: check_access failed. ",
-                "The caller may have tried to grant a permission that they don't possess."
+            .context(format!(
+                concat!(
+                    "check_grant_permission: check_access failed. ",
+                    "The caller may have tried to grant a permission that they don't possess. {:?}"
+                ),
+                p
             ))?
     }
     Ok(())
@@ -575,6 +578,16 @@
         KeyPerm::use_(),
     ];
 
+    const SYSTEM_SERVER_PERMISSIONS_NO_GRANT: KeyPermSet = key_perm_set![
+        KeyPerm::delete(),
+        KeyPerm::use_dev_id(),
+        // No KeyPerm::grant()
+        KeyPerm::get_info(),
+        KeyPerm::rebind(),
+        KeyPerm::update(),
+        KeyPerm::use_(),
+    ];
+
     const NOT_GRANT_PERMS: KeyPermSet = key_perm_set![
         KeyPerm::manage_blob(),
         KeyPerm::delete(),
@@ -643,7 +656,6 @@
         assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::add_auth()).is_ok());
         assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::clear_ns()).is_ok());
         assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::get_state()).is_ok());
-        assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::list()).is_ok());
         assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::lock()).is_ok());
         assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::reset()).is_ok());
         assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::unlock()).is_ok());
@@ -663,9 +675,10 @@
         let system_server_ctx = Context::new("u:r:system_server:s0")?;
         let shell_ctx = Context::new("u:r:shell:s0")?;
         let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
-        assert!(check_grant_permission(&system_server_ctx, NOT_GRANT_PERMS, &key).is_ok());
-        // attempts to grant the grant permission must always fail even when privileged.
+        check_grant_permission(&system_server_ctx, SYSTEM_SERVER_PERMISSIONS_NO_GRANT, &key)
+            .expect("Grant permission check failed.");
 
+        // attempts to grant the grant permission must always fail even when privileged.
         assert_perm_failed!(check_grant_permission(
             &system_server_ctx,
             KeyPerm::grant().into(),