Merge "Added TD-SCDMA bands for network scanning"
diff --git a/current.txt b/current.txt
index f7c9b45..09759b9 100644
--- a/current.txt
+++ b/current.txt
@@ -651,10 +651,10 @@
 df9c79c4fdde2821550c6d5c3d07f5ec0adfb1b702561ce543c906ddef698703 android.hardware.media.c2@1.1::IComponent
 a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardware.media.c2@1.1::IComponentStore
 4b5c8546533db9412fec6d32c0ef42b22e5e68dbf390c775ec3c22bb2d501102 android.hardware.neuralnetworks@1.3::IBuffer
-234cc547d63d2f24a447aee0a9a76cab68b31c080adadc5a960598b827a69fa2 android.hardware.neuralnetworks@1.3::IDevice
+5a6b75f13f0e010a4268defa4f627b862ab2899fb04f9d985194a25bd8f9fe0d android.hardware.neuralnetworks@1.3::IDevice
 058b48f0e2e725bb2b3fa2b7917b0f0a696383d03a4c57afe26f0eadb6a7af28 android.hardware.neuralnetworks@1.3::IPreparedModel
 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
-2576ba54711218ce0d7f207baa533fca9af3c630756938ede6e73fe197b7ea38 android.hardware.neuralnetworks@1.3::types
+12c51f9d04a52324510419aeee3e37bb3607e6900556cdde79774d80ed989855 android.hardware.neuralnetworks@1.3::types
 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
 c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd
 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types
diff --git a/keymaster/4.0/support/Android.bp b/keymaster/4.0/support/Android.bp
index 2f40282..9c5fbab 100644
--- a/keymaster/4.0/support/Android.bp
+++ b/keymaster/4.0/support/Android.bp
@@ -27,11 +27,10 @@
         "authorization_set.cpp",
         "key_param_output.cpp",
         "keymaster_utils.cpp",
-        "Keymaster.cpp",
-        "Keymaster3.cpp",
-        "Keymaster4.cpp",
     ],
-    export_include_dirs: ["include"],
+    export_include_dirs: [
+        "include",
+    ],
     shared_libs: [
         "android.hardware.keymaster@3.0",
         "android.hardware.keymaster@4.0",
@@ -39,6 +38,5 @@
         "libcrypto",
         "libhardware",
         "libhidlbase",
-        "libutils",
-    ]
+    ],
 }
diff --git a/keymaster/4.0/support/Keymaster4.cpp b/keymaster/4.0/support/Keymaster4.cpp
deleted file mode 100644
index cc3d656..0000000
--- a/keymaster/4.0/support/Keymaster4.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <keymasterV4_0/Keymaster4.h>
-
-#include <android-base/logging.h>
-
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
-
-void Keymaster4::getVersionIfNeeded() {
-    if (haveVersion_) return;
-
-    auto rc =
-        dev_->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& keymasterName,
-                                  const hidl_string& authorName) {
-            version_ = {keymasterName, authorName, 4 /* major version */, securityLevel,
-                        true /* supportsEc */};
-            haveVersion_ = true;
-        });
-
-    CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware info";
-}
-
-}  // namespace support
-}  // namespace V4_0
-}  // namespace keymaster
-}  // namespace hardware
-}  // namespace android
diff --git a/keymaster/4.0/support/OWNERS b/keymaster/4.0/support/OWNERS
index 335660d..a9efe66 100644
--- a/keymaster/4.0/support/OWNERS
+++ b/keymaster/4.0/support/OWNERS
@@ -1,2 +1,3 @@
 jdanis@google.com
 swillden@google.com
+jbires@google.com
diff --git a/keymaster/4.0/support/attestation_record.cpp b/keymaster/4.0/support/attestation_record.cpp
index 000d46e..27e00c1 100644
--- a/keymaster/4.0/support/attestation_record.cpp
+++ b/keymaster/4.0/support/attestation_record.cpp
@@ -321,19 +321,20 @@
         LOG(ERROR) << AT << "Failed record parsing";
         return ErrorCode::UNKNOWN_ERROR;
     }
-    if (!record->tee_enforced) {
-        LOG(ERROR) << AT << "Failed hardware characteristic parsing";
+
+    KM_ROOT_OF_TRUST* root_of_trust = nullptr;
+    if (record->tee_enforced && record->tee_enforced->root_of_trust) {
+        root_of_trust = record->tee_enforced->root_of_trust;
+    } else if (record->software_enforced && record->software_enforced->root_of_trust) {
+        root_of_trust = record->software_enforced->root_of_trust;
+    } else {
+        LOG(ERROR) << AT << " Failed root of trust parsing";
         return ErrorCode::INVALID_ARGUMENT;
     }
-    if (!record->tee_enforced->root_of_trust) {
-        LOG(ERROR) << AT << "Failed root of trust parsing";
+    if (!root_of_trust->verified_boot_key) {
+        LOG(ERROR) << AT << " Failed verified boot key parsing";
         return ErrorCode::INVALID_ARGUMENT;
     }
-    if (!record->tee_enforced->root_of_trust->verified_boot_key) {
-        LOG(ERROR) << AT << "Failed verified boot key parsing";
-        return ErrorCode::INVALID_ARGUMENT;
-    }
-    KM_ROOT_OF_TRUST* root_of_trust = record->tee_enforced->root_of_trust;
 
     auto& vb_key = root_of_trust->verified_boot_key;
     verified_boot_key->resize(vb_key->length);
@@ -342,19 +343,19 @@
     *verified_boot_state = static_cast<keymaster_verified_boot_t>(
             ASN1_ENUMERATED_get(root_of_trust->verified_boot_state));
     if (!verified_boot_state) {
-        LOG(ERROR) << AT << "Failed verified boot state parsing";
+        LOG(ERROR) << AT << " Failed verified boot state parsing";
         return ErrorCode::INVALID_ARGUMENT;
     }
 
     *device_locked = root_of_trust->device_locked;
     if (!device_locked) {
-        LOG(ERROR) << AT << "Failed device locked parsing";
+        LOG(ERROR) << AT << " Failed device locked parsing";
         return ErrorCode::INVALID_ARGUMENT;
     }
 
     auto& vb_hash = root_of_trust->verified_boot_hash;
     if (!vb_hash) {
-        LOG(ERROR) << AT << "Failed verified boot hash parsing";
+        LOG(ERROR) << AT << " Failed verified boot hash parsing";
         return ErrorCode::INVALID_ARGUMENT;
     }
     verified_boot_hash->resize(vb_hash->length);
diff --git a/keymaster/4.0/support/authorization_set.cpp b/keymaster/4.0/support/authorization_set.cpp
index d6b50f5..a024ff9 100644
--- a/keymaster/4.0/support/authorization_set.cpp
+++ b/keymaster/4.0/support/authorization_set.cpp
@@ -25,7 +25,7 @@
 namespace keymaster {
 namespace V4_0 {
 
-inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
+bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
     if (a.tag != b.tag) return a.tag < b.tag;
     int retval;
     switch (typeFromTag(a.tag)) {
@@ -58,7 +58,7 @@
     return false;
 }
 
-inline bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
+bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
     if (a.tag != b.tag) return false;
 
     switch (typeFromTag(a.tag)) {
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
deleted file mode 100644
index dfd03ef..0000000
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- **
- ** Copyright 2017, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
-#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
-
-#include "Keymaster.h"
-
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
-
-using android::sp;
-using IKeymaster4Device = ::android::hardware::keymaster::V4_0::IKeymasterDevice;
-
-class Keymaster4 : public Keymaster {
-   public:
-    using WrappedIKeymasterDevice = IKeymaster4Device;
-    Keymaster4(sp<IKeymasterDevice> km4_dev, const hidl_string& instanceName)
-        : Keymaster(IKeymaster4Device::descriptor, instanceName),
-          haveVersion_(false),
-          dev_(km4_dev) {}
-
-    const VersionResult& halVersion() const override {
-        const_cast<Keymaster4*>(this)->getVersionIfNeeded();
-        return version_;
-    }
-
-    Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb) override {
-        return dev_->getHardwareInfo(_hidl_cb);
-    }
-
-    Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
-        return dev_->getHmacSharingParameters(_hidl_cb);
-    }
-
-    Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>& params,
-                                   computeSharedHmac_cb _hidl_cb) override {
-        return dev_->computeSharedHmac(params, _hidl_cb);
-    }
-
-    Return<void> verifyAuthorization(uint64_t operationHandle, const hidl_vec<KeyParameter>& params,
-                                     const HardwareAuthToken& authToken,
-                                     verifyAuthorization_cb _hidl_cb) override {
-        return dev_->verifyAuthorization(operationHandle, params, authToken, _hidl_cb);
-    }
-
-    Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override {
-        return dev_->addRngEntropy(data);
-    }
-
-    Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
-                             generateKey_cb _hidl_cb) override {
-        return dev_->generateKey(keyParams, _hidl_cb);
-    }
-
-    Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
-                                       const hidl_vec<uint8_t>& clientId,
-                                       const hidl_vec<uint8_t>& appData,
-                                       getKeyCharacteristics_cb _hidl_cb) override {
-        return dev_->getKeyCharacteristics(keyBlob, clientId, appData, _hidl_cb);
-    }
-
-    Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
-                           const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override {
-        return dev_->importKey(params, keyFormat, keyData, _hidl_cb);
-    }
-
-    Return<void> importWrappedKey(const hidl_vec<uint8_t>& wrappedKeyData,
-                                  const hidl_vec<uint8_t>& wrappingKeyBlob,
-                                  const hidl_vec<uint8_t>& maskingKey,
-                                  const hidl_vec<KeyParameter>& unwrappingParams,
-                                  uint64_t passwordSid, uint64_t biometricSid,
-                                  importWrappedKey_cb _hidl_cb) {
-        return dev_->importWrappedKey(wrappedKeyData, wrappingKeyBlob, maskingKey, unwrappingParams,
-                                      passwordSid, biometricSid, _hidl_cb);
-    }
-
-    Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
-                           const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
-                           exportKey_cb _hidl_cb) override {
-        return dev_->exportKey(exportFormat, keyBlob, clientId, appData, _hidl_cb);
-    }
-
-    Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
-                           const hidl_vec<KeyParameter>& attestParams,
-                           attestKey_cb _hidl_cb) override {
-        return dev_->attestKey(keyToAttest, attestParams, _hidl_cb);
-    }
-
-    Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
-                            const hidl_vec<KeyParameter>& upgradeParams,
-                            upgradeKey_cb _hidl_cb) override {
-        return dev_->upgradeKey(keyBlobToUpgrade, upgradeParams, _hidl_cb);
-    }
-
-    Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override {
-        return dev_->deleteKey(keyBlob);
-    }
-
-    Return<ErrorCode> deleteAllKeys() override { return dev_->deleteAllKeys(); }
-
-    Return<ErrorCode> destroyAttestationIds() override { return dev_->destroyAttestationIds(); }
-
-    Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
-                       const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
-                       begin_cb _hidl_cb) override {
-        return dev_->begin(purpose, key, inParams, authToken, _hidl_cb);
-    }
-
-    Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
-                        const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
-                        const VerificationToken& verificationToken, update_cb _hidl_cb) override {
-        return dev_->update(operationHandle, inParams, input, authToken, verificationToken,
-                            _hidl_cb);
-    }
-
-    Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
-                        const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
-                        const HardwareAuthToken& authToken,
-                        const VerificationToken& verificationToken, finish_cb _hidl_cb) override {
-        return dev_->finish(operationHandle, inParams, input, signature, authToken,
-                            verificationToken, _hidl_cb);
-    }
-
-    Return<ErrorCode> abort(uint64_t operationHandle) override {
-        return dev_->abort(operationHandle);
-    }
-
-   private:
-    void getVersionIfNeeded();
-
-    bool haveVersion_;
-    VersionResult version_;
-    sp<IKeymaster4Device> dev_;
-};
-
-}  // namespace support
-}  // namespace V4_0
-}  // namespace keymaster
-}  // namespace hardware
-}  // namespace android
-
-#endif  // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
index cb29c64..bc7f311 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
@@ -355,95 +355,61 @@
     return accessTagValue(ttag, param);
 }
 
+inline bool operator<(const KeyParameter& a, const KeyParameter& b) {
+    if (a.tag != b.tag) return a.tag < b.tag;
+    int retval;
+    switch (typeFromTag(a.tag)) {
+        case TagType::INVALID:
+        case TagType::BOOL:
+            return false;
+        case TagType::ENUM:
+        case TagType::ENUM_REP:
+        case TagType::UINT:
+        case TagType::UINT_REP:
+            return a.f.integer < b.f.integer;
+        case TagType::ULONG:
+        case TagType::ULONG_REP:
+            return a.f.longInteger < b.f.longInteger;
+        case TagType::DATE:
+            return a.f.dateTime < b.f.dateTime;
+        case TagType::BIGNUM:
+        case TagType::BYTES:
+            // Handle the empty cases.
+            if (a.blob.size() == 0) return b.blob.size() != 0;
+            if (b.blob.size() == 0) return false;
+
+            retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size()));
+            // if one is the prefix of the other the longer wins
+            if (retval == 0) return a.blob.size() < b.blob.size();
+            // Otherwise a is less if a is less.
+            else
+                return retval < 0;
+    }
+    return false;
+}
+
 inline bool operator==(const KeyParameter& a, const KeyParameter& b) {
-    if (a.tag != b.tag) {
-        return false;
-    }
+    if (a.tag != b.tag) return false;
 
-    switch (a.tag) {
-        /* Boolean tags */
-        case Tag::INVALID:
-        case Tag::CALLER_NONCE:
-        case Tag::INCLUDE_UNIQUE_ID:
-        case Tag::BOOTLOADER_ONLY:
-        case Tag::NO_AUTH_REQUIRED:
-        case Tag::ALLOW_WHILE_ON_BODY:
-        case Tag::UNLOCKED_DEVICE_REQUIRED:
-        case Tag::ROLLBACK_RESISTANCE:
-        case Tag::RESET_SINCE_ID_ROTATION:
-        case Tag::TRUSTED_CONFIRMATION_REQUIRED:
-        case Tag::TRUSTED_USER_PRESENCE_REQUIRED:
+    switch (typeFromTag(a.tag)) {
+        case TagType::INVALID:
+        case TagType::BOOL:
             return true;
-
-        /* Integer tags */
-        case Tag::KEY_SIZE:
-        case Tag::MIN_MAC_LENGTH:
-        case Tag::MIN_SECONDS_BETWEEN_OPS:
-        case Tag::MAX_USES_PER_BOOT:
-        case Tag::OS_VERSION:
-        case Tag::OS_PATCHLEVEL:
-        case Tag::MAC_LENGTH:
-        case Tag::USER_ID:
-        case Tag::AUTH_TIMEOUT:
-        case Tag::VENDOR_PATCHLEVEL:
-        case Tag::BOOT_PATCHLEVEL:
+        case TagType::ENUM:
+        case TagType::ENUM_REP:
+        case TagType::UINT:
+        case TagType::UINT_REP:
             return a.f.integer == b.f.integer;
-
-        /* Long integer tags */
-        case Tag::RSA_PUBLIC_EXPONENT:
-        case Tag::USER_SECURE_ID:
+        case TagType::ULONG:
+        case TagType::ULONG_REP:
             return a.f.longInteger == b.f.longInteger;
-
-        /* Date-time tags */
-        case Tag::ACTIVE_DATETIME:
-        case Tag::ORIGINATION_EXPIRE_DATETIME:
-        case Tag::USAGE_EXPIRE_DATETIME:
-        case Tag::CREATION_DATETIME:
+        case TagType::DATE:
             return a.f.dateTime == b.f.dateTime;
-
-        /* Bytes tags */
-        case Tag::APPLICATION_ID:
-        case Tag::APPLICATION_DATA:
-        case Tag::ROOT_OF_TRUST:
-        case Tag::UNIQUE_ID:
-        case Tag::ATTESTATION_CHALLENGE:
-        case Tag::ATTESTATION_APPLICATION_ID:
-        case Tag::ATTESTATION_ID_BRAND:
-        case Tag::ATTESTATION_ID_DEVICE:
-        case Tag::ATTESTATION_ID_PRODUCT:
-        case Tag::ATTESTATION_ID_SERIAL:
-        case Tag::ATTESTATION_ID_IMEI:
-        case Tag::ATTESTATION_ID_MEID:
-        case Tag::ATTESTATION_ID_MANUFACTURER:
-        case Tag::ATTESTATION_ID_MODEL:
-        case Tag::ASSOCIATED_DATA:
-        case Tag::CONFIRMATION_TOKEN:
-        case Tag::NONCE:
-            return a.blob == b.blob;
-
-        /* Enum tags */
-        case Tag::PURPOSE:
-            return a.f.purpose == b.f.purpose;
-        case Tag::ALGORITHM:
-            return a.f.algorithm == b.f.algorithm;
-        case Tag::BLOCK_MODE:
-            return a.f.blockMode == b.f.blockMode;
-        case Tag::DIGEST:
-            return a.f.digest == b.f.digest;
-        case Tag::PADDING:
-            return a.f.paddingMode == b.f.paddingMode;
-        case Tag::EC_CURVE:
-            return a.f.ecCurve == b.f.ecCurve;
-        case Tag::BLOB_USAGE_REQUIREMENTS:
-            return a.f.keyBlobUsageRequirements == b.f.keyBlobUsageRequirements;
-        case Tag::USER_AUTH_TYPE:
-            return a.f.integer == b.f.integer;
-        case Tag::ORIGIN:
-            return a.f.origin == b.f.origin;
-        case Tag::HARDWARE_TYPE:
-            return a.f.hardwareType == b.f.hardwareType;
+        case TagType::BIGNUM:
+        case TagType::BYTES:
+            if (a.blob.size() != b.blob.size()) return false;
+            return a.blob.size() == 0 || memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0;
     }
-
     return false;
 }
 
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
index 5e5ae8d..61645f8 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
@@ -52,6 +52,9 @@
 HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer);
 hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token);
 
+uint32_t getOsVersion();
+uint32_t getOsPatchlevel();
+
 }  // namespace support
 }  // namespace V4_0
 }  // namespace keymaster
diff --git a/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h b/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h
index cc71dd1..b3869f4 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h
@@ -18,6 +18,8 @@
 #define HARDWARE_INTERFACES_KEYMASTER_4_0_SUPPORT_OPENSSL_UTILS_H_
 
 #include <android/hardware/keymaster/4.0/types.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
 
 template <typename T, void (*F)(T*)>
 struct UniquePtrDeleter {
diff --git a/keymaster/4.0/support/keymaster_utils.cpp b/keymaster/4.0/support/keymaster_utils.cpp
index e35fdd3..850a776 100644
--- a/keymaster/4.0/support/keymaster_utils.cpp
+++ b/keymaster/4.0/support/keymaster_utils.cpp
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
+#include <regex.h>
+
+#include <android-base/properties.h>
 #include <hardware/hw_auth_token.h>
 #include <keymasterV4_0/keymaster_utils.h>
 
-namespace android {
-namespace hardware {
+namespace android::hardware {
 
 inline static bool operator<(const hidl_vec<uint8_t>& a, const hidl_vec<uint8_t>& b) {
     auto result = memcmp(a.data(), b.data(), std::min(a.size(), b.size()));
@@ -32,8 +34,7 @@
     return memcmp(a.data(), b.data(), SIZE) == -1;
 }
 
-namespace keymaster {
-namespace V4_0 {
+namespace keymaster::V4_0 {
 
 bool operator<(const HmacSharingParameters& a, const HmacSharingParameters& b) {
     return std::tie(a.seed, a.nonce) < std::tie(b.seed, b.nonce);
@@ -58,9 +59,9 @@
 
 hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token) {
     static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
-                          sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
-                          sizeof(token.timestamp) + kHmacSize ==
-                      sizeof(hw_auth_token_t),
+                                  sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
+                                  sizeof(token.timestamp) + kHmacSize ==
+                          sizeof(hw_auth_token_t),
                   "HardwareAuthToken content size does not match hw_auth_token_t size");
 
     hidl_vec<uint8_t> result;
@@ -86,9 +87,9 @@
 HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer) {
     HardwareAuthToken token;
     static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
-                          sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
-                          sizeof(token.timestamp) + kHmacSize ==
-                      sizeof(hw_auth_token_t),
+                                  sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
+                                  sizeof(token.timestamp) + kHmacSize ==
+                          sizeof(hw_auth_token_t),
                   "HardwareAuthToken content size does not match hw_auth_token_t size");
 
     if (buffer.size() != sizeof(hw_auth_token_t)) return {};
@@ -100,7 +101,7 @@
     pos = copy_bytes_from_iterator(&token.authenticatorId, pos);
     pos = copy_bytes_from_iterator(&token.authenticatorType, pos);
     token.authenticatorType = static_cast<HardwareAuthenticatorType>(
-        ntohl(static_cast<uint32_t>(token.authenticatorType)));
+            ntohl(static_cast<uint32_t>(token.authenticatorType)));
     pos = copy_bytes_from_iterator(&token.timestamp, pos);
     token.timestamp = ntohq(token.timestamp);
     token.mac.resize(kHmacSize);
@@ -109,8 +110,93 @@
     return token;
 }
 
+namespace {
+
+constexpr char kPlatformVersionProp[] = "ro.build.version.release";
+constexpr char kPlatformVersionRegex[] = "^([0-9]{1,2})(\\.([0-9]{1,2}))?(\\.([0-9]{1,2}))?";
+constexpr size_t kMajorVersionMatch = 1;
+constexpr size_t kMinorVersionMatch = 3;
+constexpr size_t kSubminorVersionMatch = 5;
+constexpr size_t kPlatformVersionMatchCount = kSubminorVersionMatch + 1;
+
+constexpr char kPlatformPatchlevelProp[] = "ro.build.version.security_patch";
+constexpr char kPlatformPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-[0-9]{2}$";
+constexpr size_t kYearMatch = 1;
+constexpr size_t kMonthMatch = 2;
+constexpr size_t kPlatformPatchlevelMatchCount = kMonthMatch + 1;
+
+uint32_t match_to_uint32(const char* expression, const regmatch_t& match) {
+    if (match.rm_so == -1) return 0;
+
+    size_t len = match.rm_eo - match.rm_so;
+    std::string s(expression + match.rm_so, len);
+    return std::stoul(s);
+}
+
+std::string wait_and_get_property(const char* prop) {
+    std::string prop_value;
+    while (!android::base::WaitForPropertyCreation(prop))
+        ;
+    prop_value = android::base::GetProperty(prop, "" /* default */);
+    return prop_value;
+}
+
+}  // anonymous namespace
+
+uint32_t getOsVersion(const char* version_str) {
+    regex_t regex;
+    if (regcomp(&regex, kPlatformVersionRegex, REG_EXTENDED)) {
+        return 0;
+    }
+
+    regmatch_t matches[kPlatformVersionMatchCount];
+    int not_match =
+            regexec(&regex, version_str, kPlatformVersionMatchCount, matches, 0 /* flags */);
+    regfree(&regex);
+    if (not_match) {
+        return 0;
+    }
+
+    uint32_t major = match_to_uint32(version_str, matches[kMajorVersionMatch]);
+    uint32_t minor = match_to_uint32(version_str, matches[kMinorVersionMatch]);
+    uint32_t subminor = match_to_uint32(version_str, matches[kSubminorVersionMatch]);
+
+    return (major * 100 + minor) * 100 + subminor;
+}
+
+uint32_t getOsVersion() {
+    std::string version = wait_and_get_property(kPlatformVersionProp);
+    return getOsVersion(version.c_str());
+}
+
+uint32_t getOsPatchlevel(const char* patchlevel_str) {
+    regex_t regex;
+    if (regcomp(&regex, kPlatformPatchlevelRegex, REG_EXTENDED) != 0) {
+        return 0;
+    }
+
+    regmatch_t matches[kPlatformPatchlevelMatchCount];
+    int not_match =
+            regexec(&regex, patchlevel_str, kPlatformPatchlevelMatchCount, matches, 0 /* flags */);
+    regfree(&regex);
+    if (not_match) {
+        return 0;
+    }
+
+    uint32_t year = match_to_uint32(patchlevel_str, matches[kYearMatch]);
+    uint32_t month = match_to_uint32(patchlevel_str, matches[kMonthMatch]);
+
+    if (month < 1 || month > 12) {
+        return 0;
+    }
+    return year * 100 + month;
+}
+
+uint32_t getOsPatchlevel() {
+    std::string patchlevel = wait_and_get_property(kPlatformPatchlevelProp);
+    return getOsPatchlevel(patchlevel.c_str());
+}
+
 }  // namespace support
-}  // namespace V4_0
-}  // namespace keymaster
-}  // namespace hardware
-}  // namespace android
+}  // namespace keymaster::V4_0
+}  // namespace android::hardware
diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp
index 5649f20..db50080 100644
--- a/keymaster/4.0/vts/functional/Android.bp
+++ b/keymaster/4.0/vts/functional/Android.bp
@@ -19,7 +19,6 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "HmacKeySharingTest.cpp",
-        "KeymasterHidlTest.cpp",
         "VerificationTokenTest.cpp",
         "keymaster_hidl_hal_test.cpp",
     ],
@@ -27,7 +26,25 @@
         "android.hardware.keymaster@4.0",
         "libcrypto_static",
         "libkeymaster4support",
-        "libsoftkeymasterdevice",
+        "libkeymaster4vtstest",
     ],
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
+}
+
+cc_test_library {
+    name: "libkeymaster4vtstest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "KeymasterHidlTest.cpp",
+    ],
+    export_include_dirs: [
+        ".",
+    ],
+    static_libs: [
+        "android.hardware.keymaster@4.0",
+        "libkeymaster4support",
+    ],
 }
diff --git a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
index c228ef7..f57a668 100644
--- a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
+++ b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
@@ -28,6 +28,16 @@
  */
 class HmacKeySharingTest : public KeymasterHidlTest {
    protected:
+     const std::vector<sp<IKeymasterDevice>>& allKeymasters() {
+         if (all_keymasters_.empty()) {
+             auto names = android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor);
+             for (const auto& name : names) {
+                 all_keymasters_.push_back(IKeymasterDevice::getService(name));
+             }
+         }
+         return all_keymasters_;
+     }
+
     struct GetParamsResult {
         ErrorCode error;
         HmacSharingParameters params;
@@ -99,8 +109,13 @@
             EXPECT_EQ(expected, response.sharing_check) << "Sharing check values should match.";
         }
     }
+
+  private:
+    static std::vector<sp<IKeymasterDevice>> all_keymasters_;
 };
 
+std::vector<sp<IKeymasterDevice>> HmacKeySharingTest::all_keymasters_;
+
 TEST_P(HmacKeySharingTest, GetParameters) {
     auto result1 = getHmacSharingParameters(keymaster());
     EXPECT_EQ(ErrorCode::OK, result1.error);
@@ -115,26 +130,26 @@
 }
 
 TEST_P(HmacKeySharingTest, ComputeSharedHmac) {
-    auto params = getHmacSharingParameters(all_keymasters());
-    ASSERT_EQ(all_keymasters().size(), params.size())
-        << "One or more keymasters failed to provide parameters.";
+    auto params = getHmacSharingParameters(allKeymasters());
+    ASSERT_EQ(allKeymasters().size(), params.size())
+            << "One or more keymasters failed to provide parameters.";
 
     auto nonces = copyNonces(params);
-    EXPECT_EQ(all_keymasters().size(), nonces.size());
+    EXPECT_EQ(allKeymasters().size(), nonces.size());
     std::sort(nonces.begin(), nonces.end());
     std::unique(nonces.begin(), nonces.end());
-    EXPECT_EQ(all_keymasters().size(), nonces.size());
+    EXPECT_EQ(allKeymasters().size(), nonces.size());
 
-    auto responses = computeSharedHmac(all_keymasters(), params);
+    auto responses = computeSharedHmac(allKeymasters(), params);
     ASSERT_GT(responses.size(), 0U);
     verifyResponses(responses[0].sharing_check, responses);
 
     // Do it a second time.  Should get the same answers.
-    params = getHmacSharingParameters(all_keymasters());
-    ASSERT_EQ(all_keymasters().size(), params.size())
-        << "One or more keymasters failed to provide parameters.";
+    params = getHmacSharingParameters(allKeymasters());
+    ASSERT_EQ(allKeymasters().size(), params.size())
+            << "One or more keymasters failed to provide parameters.";
 
-    responses = computeSharedHmac(all_keymasters(), params);
+    responses = computeSharedHmac(allKeymasters(), params);
     ASSERT_GT(responses.size(), 0U);
     ASSERT_EQ(32U, responses[0].sharing_check.size());
     verifyResponses(responses[0].sharing_check, responses);
@@ -160,15 +175,16 @@
     // sync with respect to the HMAC key.  Granted that VTS tests aren't run on in-use production
     // devices, this still has the potential to cause confusion.  To mitigate that, we always
     // (barring crashes :-/) re-run the unmodified agreement process on our way out.
-    auto fixup_hmac = finally(
-        [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); });
+    auto fixup_hmac = finally([&]() {
+        computeSharedHmac(allKeymasters(), getHmacSharingParameters(allKeymasters()));
+    });
 
-    auto params = getHmacSharingParameters(all_keymasters());
-    ASSERT_EQ(all_keymasters().size(), params.size())
-        << "One or more keymasters failed to provide parameters.";
+    auto params = getHmacSharingParameters(allKeymasters());
+    ASSERT_EQ(allKeymasters().size(), params.size())
+            << "One or more keymasters failed to provide parameters.";
 
     // All should be well in the normal case
-    auto responses = computeSharedHmac(all_keymasters(), params);
+    auto responses = computeSharedHmac(allKeymasters(), params);
 
     ASSERT_GT(responses.size(), 0U);
     HidlBuf correct_response = responses[0].sharing_check;
@@ -181,7 +197,7 @@
     uint8_t bit_to_tweak = rand() % 8;
     params[param_to_tweak].nonce[byte_to_tweak] ^= (1 << bit_to_tweak);
 
-    responses = computeSharedHmac(all_keymasters(), params);
+    responses = computeSharedHmac(allKeymasters(), params);
     for (size_t i = 0; i < responses.size(); ++i) {
         if (i == param_to_tweak) {
             EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
@@ -199,15 +215,16 @@
     // sync with respect to the HMAC key.  Granted that VTS tests aren't run on in-use production
     // devices, this still has the potential to cause confusion.  To mitigate that, we always
     // (barring crashes :-/) re-run the unmodified agreement process on our way out.
-    auto fixup_hmac = finally(
-        [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); });
+    auto fixup_hmac = finally([&]() {
+        computeSharedHmac(allKeymasters(), getHmacSharingParameters(allKeymasters()));
+    });
 
-    auto params = getHmacSharingParameters(all_keymasters());
-    ASSERT_EQ(all_keymasters().size(), params.size())
-        << "One or more keymasters failed to provide parameters.";
+    auto params = getHmacSharingParameters(allKeymasters());
+    ASSERT_EQ(allKeymasters().size(), params.size())
+            << "One or more keymasters failed to provide parameters.";
 
     // All should be well in the normal case
-    auto responses = computeSharedHmac(all_keymasters(), params);
+    auto responses = computeSharedHmac(allKeymasters(), params);
 
     ASSERT_GT(responses.size(), 0U);
     HidlBuf correct_response = responses[0].sharing_check;
@@ -223,7 +240,7 @@
     }
     to_tweak[0]++;
 
-    responses = computeSharedHmac(all_keymasters(), params);
+    responses = computeSharedHmac(allKeymasters(), params);
     for (size_t i = 0; i < responses.size(); ++i) {
         if (i == param_to_tweak) {
             EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
@@ -236,10 +253,7 @@
     }
 }
 
-INSTANTIATE_TEST_SUITE_P(
-        PerInstance, HmacKeySharingTest,
-        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor)),
-        android::hardware::PrintInstanceNameToString);
+INSTANTIATE_KEYMASTER_HIDL_TEST(HmacKeySharingTest);
 
 }  // namespace test
 }  // namespace V4_0
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
index 7241984..d0ad433 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
@@ -23,6 +23,7 @@
 #include <android/hidl/manager/1.0/IServiceManager.h>
 
 #include <keymasterV4_0/key_param_output.h>
+#include <keymasterV4_0/keymaster_utils.h>
 
 namespace android {
 namespace hardware {
@@ -41,39 +42,26 @@
 
 namespace test {
 
-void KeymasterHidlTest::InitializeKeymaster() {
-    service_name_ = GetParam();
-    keymaster_ = IKeymasterDevice::getService(service_name_);
-    ASSERT_NE(keymaster_, nullptr);
+using namespace std::literals::chrono_literals;
 
+void KeymasterHidlTest::InitializeKeymaster(sp<IKeymasterDevice> keymaster) {
+    ASSERT_NE(keymaster, nullptr);
+    keymaster_ = keymaster;
     ASSERT_TRUE(keymaster_
-                    ->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name,
-                                          const hidl_string& author) {
-                        securityLevel_ = securityLevel;
-                        name_ = name;
-                        author_ = author;
-                    })
-                    .isOk());
+                        ->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name,
+                                              const hidl_string& author) {
+                            securityLevel_ = securityLevel;
+                            name_ = name;
+                            author_ = author;
+                        })
+                        .isOk());
+
+    os_version_ = support::getOsVersion();
+    os_patch_level_ = support::getOsPatchlevel();
 }
 
 void KeymasterHidlTest::SetUp() {
-    InitializeKeymaster();
-
-    os_version_ = ::keymaster::GetOsVersion();
-    os_patch_level_ = ::keymaster::GetOsPatchlevel();
-
-    auto service_manager = android::hidl::manager::V1_0::IServiceManager::getService();
-    ASSERT_NE(nullptr, service_manager.get());
-    all_keymasters_.push_back(keymaster_);
-    service_manager->listByInterface(
-        IKeymasterDevice::descriptor, [&](const hidl_vec<hidl_string>& names) {
-            for (auto& name : names) {
-                if (name == service_name_) continue;
-                auto keymaster = IKeymasterDevice::getService(name);
-                ASSERT_NE(keymaster, nullptr);
-                all_keymasters_.push_back(keymaster);
-            }
-        });
+    InitializeKeymaster(IKeymasterDevice::getService(GetParam()));
 }
 
 ErrorCode KeymasterHidlTest::GenerateKey(const AuthorizationSet& key_desc, HidlBuf* key_blob,
@@ -138,7 +126,7 @@
                                               string masking_key,
                                               const AuthorizationSet& unwrapping_params) {
     ErrorCode error;
-    ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key);
+    EXPECT_EQ(ErrorCode::OK, ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key));
     EXPECT_TRUE(keymaster_
                     ->importWrappedKey(HidlBuf(wrapped_key), key_blob_, HidlBuf(masking_key),
                                        unwrapping_params.hidl_data(), 0 /* passwordSid */,
@@ -207,7 +195,9 @@
     HidlBuf empty_buf = {};
     EXPECT_EQ(ErrorCode::OK,
               GetCharacteristics(key_blob, client_id, app_data, key_characteristics));
-    EXPECT_GT(key_characteristics->hardwareEnforced.size(), 0);
+    if (SecLevel() != SecurityLevel::SOFTWARE) {
+        EXPECT_GT(key_characteristics->hardwareEnforced.size(), 0);
+    }
     EXPECT_GT(key_characteristics->softwareEnforced.size(), 0);
 
     EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
@@ -647,23 +637,25 @@
     switch (algorithm) {
         case Algorithm::RSA:
             switch (SecLevel()) {
+                case SecurityLevel::SOFTWARE:
                 case SecurityLevel::TRUSTED_ENVIRONMENT:
                     return {2048, 3072, 4096};
                 case SecurityLevel::STRONGBOX:
                     return {2048};
                 default:
-                    CHECK(false) << "Invalid security level " << uint32_t(SecLevel());
+                    ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
                     break;
             }
             break;
         case Algorithm::EC:
             switch (SecLevel()) {
+                case SecurityLevel::SOFTWARE:
                 case SecurityLevel::TRUSTED_ENVIRONMENT:
                     return {224, 256, 384, 521};
                 case SecurityLevel::STRONGBOX:
                     return {256};
                 default:
-                    CHECK(false) << "Invalid security level " << uint32_t(SecLevel());
+                    ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
                     break;
             }
             break;
@@ -678,25 +670,27 @@
             return retval;
         }
         default:
-            CHECK(false) << "Invalid Algorithm: " << algorithm;
+            ADD_FAILURE() << "Invalid Algorithm: " << algorithm;
             return {};
     }
-    CHECK(false) << "Should be impossible to get here";
+    ADD_FAILURE() << "Should be impossible to get here";
     return {};
 }
+
 std::vector<uint32_t> KeymasterHidlTest::InvalidKeySizes(Algorithm algorithm) {
-    if (SecLevel() == SecurityLevel::TRUSTED_ENVIRONMENT) return {};
-    CHECK(SecLevel() == SecurityLevel::STRONGBOX);
-    switch (algorithm) {
-        case Algorithm::RSA:
-            return {3072, 4096};
-        case Algorithm::EC:
-            return {224, 384, 521};
-        case Algorithm::AES:
-            return {192};
-        default:
-            return {};
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        switch (algorithm) {
+            case Algorithm::RSA:
+                return {3072, 4096};
+            case Algorithm::EC:
+                return {224, 384, 521};
+            case Algorithm::AES:
+                return {192};
+            default:
+                return {};
+        }
     }
+    return {};
 }
 
 std::vector<EcCurve> KeymasterHidlTest::ValidCurves() {
@@ -715,6 +709,7 @@
 
 std::vector<Digest> KeymasterHidlTest::ValidDigests(bool withNone, bool withMD5) {
     switch (SecLevel()) {
+        case SecurityLevel::SOFTWARE:
         case SecurityLevel::TRUSTED_ENVIRONMENT:
             if (withNone) {
                 if (withMD5)
@@ -740,10 +735,10 @@
                 return {Digest::SHA_2_256};
             break;
         default:
-            CHECK(false) << "Invalid security level " << uint32_t(SecLevel());
+            ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
             break;
     }
-    CHECK(false) << "Should be impossible to get here";
+    ADD_FAILURE() << "Should be impossible to get here";
     return {};
 }
 
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
index 4bd8b26..f495516 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
@@ -21,7 +21,6 @@
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
-#include <keymaster/keymaster_configuration.h>
 
 #include <keymasterV4_0/authorization_set.h>
 
@@ -35,16 +34,18 @@
 namespace test {
 
 using ::android::sp;
-using ::std::string;
 using hidl::base::V1_0::DebugInfo;
+using ::std::string;
 
 class HidlBuf : public hidl_vec<uint8_t> {
-    typedef hidl_vec<uint8_t> super;
+    using super = hidl_vec<uint8_t>;
 
-   public:
+  public:
     HidlBuf() {}
     HidlBuf(const super& other) : super(other) {}
-    HidlBuf(super&& other) : super(std::move(other)) {}
+    HidlBuf(super&& other) : super(std::move(other)) { other = {}; }
+    HidlBuf(const HidlBuf& other) : super(other) {}
+    HidlBuf(HidlBuf&& other) : super(std::move(other)) { other = HidlBuf(); }
     explicit HidlBuf(const std::string& other) : HidlBuf() { *this = other; }
 
     HidlBuf& operator=(const super& other) {
@@ -54,6 +55,18 @@
 
     HidlBuf& operator=(super&& other) {
         super::operator=(std::move(other));
+        other = {};
+        return *this;
+    }
+
+    HidlBuf& operator=(const HidlBuf& other) {
+        super::operator=(other);
+        return *this;
+    }
+
+    HidlBuf& operator=(HidlBuf&& other) {
+        super::operator=(std::move(other));
+        other.super::operator=({});
         return *this;
     }
 
@@ -70,20 +83,16 @@
 
 class KeymasterHidlTest : public ::testing::TestWithParam<std::string> {
   public:
-    void SetUp();
+    void SetUp() override;
     void TearDown() override {
         if (key_blob_.size()) {
             CheckedDeleteKey();
         }
         AbortIfNeeded();
-        keymaster_.clear();
-        all_keymasters_.clear();
     }
 
-    void InitializeKeymaster();
-
+    void InitializeKeymaster(sp<IKeymasterDevice> keymaster);
     IKeymasterDevice& keymaster() { return *keymaster_; }
-    const std::vector<sp<IKeymasterDevice>>& all_keymasters() { return all_keymasters_; }
     uint32_t os_version() { return os_version_; }
     uint32_t os_patch_level() { return os_patch_level_; }
 
@@ -209,18 +218,26 @@
     KeyCharacteristics key_characteristics_;
     OperationHandle op_handle_ = kOpHandleSentinel;
 
-   private:
-     sp<IKeymasterDevice> keymaster_;
-     std::vector<sp<IKeymasterDevice>> all_keymasters_;
-     uint32_t os_version_;
-     uint32_t os_patch_level_;
+    static std::vector<std::string> build_params() {
+        auto params = android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor);
+        return params;
+    }
 
-     SecurityLevel securityLevel_;
-     hidl_string name_;
-     hidl_string author_;
-     string service_name_;
+  private:
+    sp<IKeymasterDevice> keymaster_;
+    uint32_t os_version_;
+    uint32_t os_patch_level_;
+
+    SecurityLevel securityLevel_;
+    hidl_string name_;
+    hidl_string author_;
 };
 
+#define INSTANTIATE_KEYMASTER_HIDL_TEST(name)                                      \
+    INSTANTIATE_TEST_SUITE_P(PerInstance, name,                                    \
+                             testing::ValuesIn(KeymasterHidlTest::build_params()), \
+                             android::hardware::PrintInstanceNameToString)
+
 }  // namespace test
 }  // namespace V4_0
 }  // namespace keymaster
diff --git a/keymaster/4.0/vts/functional/VerificationTokenTest.cpp b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
index 693f4ae..bab1439 100644
--- a/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
+++ b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
@@ -185,10 +185,7 @@
               memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size()));
 }
 
-INSTANTIATE_TEST_SUITE_P(
-        PerInstance, VerificationTokenTest,
-        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor)),
-        android::hardware::PrintInstanceNameToString);
+INSTANTIATE_KEYMASTER_HIDL_TEST(VerificationTokenTest);
 
 }  // namespace test
 }  // namespace V4_0
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 66132ad..6cbe4da 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -352,11 +352,11 @@
     EXPECT_EQ(ErrorCode::OK, error);
     if (error != ErrorCode::OK) return false;
 
-    EXPECT_TRUE(att_attestation_version == 3);
+    EXPECT_GE(att_attestation_version, 3U);
 
     expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, HidlBuf(app_id));
 
-    EXPECT_EQ(att_keymaster_version, 4U);
+    EXPECT_GE(att_keymaster_version, 4U);
     EXPECT_EQ(security_level, att_keymaster_security_level);
     EXPECT_EQ(security_level, att_attestation_security_level);
 
@@ -397,10 +397,16 @@
     // true. A provided boolean tag that can be pulled back out of the certificate indicates correct
     // encoding. No need to check if it's in both lists, since the AuthorizationSet compare below
     // will handle mismatches of tags.
-    EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+    if (security_level == SecurityLevel::SOFTWARE) {
+        EXPECT_TRUE(expected_sw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+    } else {
+        EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+    }
 
     // Alternatively this checks the opposite - a false boolean tag (one that isn't provided in
     // the authorization list during key generation) isn't being attested to in the certificate.
+    EXPECT_FALSE(expected_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
+    EXPECT_FALSE(att_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
     EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
     EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
 
@@ -461,10 +467,10 @@
                             verified_boot_key.size()));
     } else if (!strcmp(property_value, "red")) {
         EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_FAILED);
-        EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
-                            verified_boot_key.size()));
     } else {
-        EXPECT_TRUE(false);
+        EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_UNVERIFIED);
+        EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+                            verified_boot_key.size()));
     }
 
     att_sw_enforced.Sort();
@@ -840,6 +846,8 @@
                               .Authorization(TAG_MIN_MAC_LENGTH, 128)));
 }
 
+INSTANTIATE_KEYMASTER_HIDL_TEST(NewKeyGenerationTest);
+
 typedef KeymasterHidlTest SigningOperationsTest;
 
 /*
@@ -1509,6 +1517,8 @@
     }
 }
 
+INSTANTIATE_KEYMASTER_HIDL_TEST(SigningOperationsTest);
+
 typedef KeymasterHidlTest VerificationOperationsTest;
 
 /*
@@ -1749,6 +1759,8 @@
     CheckedDeleteKey(&verification_key);
 }
 
+INSTANTIATE_KEYMASTER_HIDL_TEST(VerificationOperationsTest);
+
 typedef KeymasterHidlTest ExportKeyTest;
 
 /*
@@ -1828,6 +1840,8 @@
     EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_FORMAT, ExportKey(KeyFormat::RAW, &export_data));
 }
 
+INSTANTIATE_KEYMASTER_HIDL_TEST(ExportKeyTest);
+
 class ImportKeyTest : public KeymasterHidlTest {
    public:
     template <TagType tag_type, Tag tag, typename ValueT>
@@ -2093,6 +2107,8 @@
     VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
 }
 
+INSTANTIATE_KEYMASTER_HIDL_TEST(ImportKeyTest);
+
 auto wrapped_key = hex2str(
     "3082017902010004820100934bf94e2aa28a3f83c9f79297250262fbe3276b5a1c91159bbfa3ef8957aac84b59b30b"
     "455a79c2973480823d8b3863c3deef4a8e243590268d80e18751a0e130f67ce6a1ace9f79b95e097474febc981195b"
@@ -2214,6 +2230,8 @@
                       .Padding(PaddingMode::RSA_OAEP)));
 }
 
+INSTANTIATE_KEYMASTER_HIDL_TEST(ImportWrappedKeyTest);
+
 typedef KeymasterHidlTest EncryptionOperationsTest;
 
 /*
@@ -4111,6 +4129,8 @@
     EXPECT_EQ(message, plaintext);
 }
 
+INSTANTIATE_KEYMASTER_HIDL_TEST(EncryptionOperationsTest);
+
 typedef KeymasterHidlTest MaxOperationsTest;
 
 /*
@@ -4166,6 +4186,8 @@
     EXPECT_EQ(ErrorCode::KEY_MAX_OPS_EXCEEDED, Begin(KeyPurpose::SIGN, params));
 }
 
+INSTANTIATE_KEYMASTER_HIDL_TEST(MaxOperationsTest);
+
 typedef KeymasterHidlTest AddEntropyTest;
 
 /*
@@ -4196,6 +4218,8 @@
     EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf(string(2 * 1024, 'a'))));
 }
 
+INSTANTIATE_KEYMASTER_HIDL_TEST(AddEntropyTest);
+
 typedef KeymasterHidlTest AttestationTest;
 
 /*
@@ -4373,6 +4397,8 @@
                         &cert_chain));
 }
 
+INSTANTIATE_KEYMASTER_HIDL_TEST(AttestationTest);
+
 typedef KeymasterHidlTest KeyDeletionTest;
 
 /**
@@ -4478,6 +4504,8 @@
     }
 }
 
+INSTANTIATE_KEYMASTER_HIDL_TEST(KeyDeletionTest);
+
 using UpgradeKeyTest = KeymasterHidlTest;
 
 /*
@@ -4497,6 +4525,8 @@
     EXPECT_EQ(result, std::make_pair(ErrorCode::OK, HidlBuf()));
 }
 
+INSTANTIATE_KEYMASTER_HIDL_TEST(UpgradeKeyTest);
+
 using ClearOperationsTest = KeymasterHidlTest;
 
 /*
@@ -4533,51 +4563,14 @@
     AbortIfNeeded();
 }
 
-/*
- * ClearSlotsTest.ServiceDeath
- *
- * Verifies that the service is restarted after death and the ongoing
- * operations are cleared.
- */
-TEST_P(ClearOperationsTest, ServiceDeath) {
-    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                             .Authorization(TAG_NO_AUTH_REQUIRED)
-                                             .RsaEncryptionKey(2048, 65537)
-                                             .Padding(PaddingMode::NONE)));
-
-    auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
-    int max_operations = SecLevel() == SecurityLevel::STRONGBOX ? 4 : 16;
-    OperationHandle op_handles[max_operations];
-    AuthorizationSet out_params;
-    for(int i=0; i<max_operations; i++) {
-        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &(op_handles[i])));
-    }
-    EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS,
-         Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &op_handle_));
-
-    DebugInfo debug_info;
-    GetDebugInfo(&debug_info);
-    kill(debug_info.pid, SIGKILL);
-    // wait 1 second for keymaster to restart
-    sleep(1);
-    InitializeKeymaster();
-
-    for(int i=0; i<max_operations; i++) {
-        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &(op_handles[i])));
-    }
-    EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS,
-         Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, &op_handle_));
-    for(int i=0; i<max_operations; i++) {
-        EXPECT_EQ(ErrorCode::OK, Abort(op_handles[i]));
-    }
-}
+INSTANTIATE_KEYMASTER_HIDL_TEST(ClearOperationsTest);
 
 typedef KeymasterHidlTest TransportLimitTest;
 
 /*
- * TransportLimitTest.LargeFinishInput
+ * TransportLimitTest.FinishInput
  *
- * Verifies that passing large input data to finish either succeeds or fails as expected.
+ * Verifies that passing input data to finish succeeds as expected.
  */
 TEST_P(TransportLimitTest, LargeFinishInput) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
@@ -4586,7 +4579,7 @@
                                                  .BlockMode(BlockMode::ECB)
                                                  .Padding(PaddingMode::NONE)));
 
-    for (int msg_size = 10 /*1KB*/; msg_size <= 17 /*128KB*/; msg_size++) {
+    for (int msg_size = 8 /* 256 bytes */; msg_size <= 11 /* 2 KiB */; msg_size++) {
         auto cipher_params =
                 AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
 
@@ -4597,71 +4590,22 @@
         string encrypted_message;
         auto rc = Finish(plain_message, &encrypted_message);
 
-        if (rc == ErrorCode::OK) {
-            EXPECT_EQ(plain_message.size(), encrypted_message.size())
-                    << "Encrypt finish returned OK, but did not consume all of the given input";
-        } else {
-            EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, rc)
-                    << "Encrypt finish failed in an unexpected way when given a large input";
-            continue;
-        }
+        EXPECT_EQ(ErrorCode::OK, rc);
+        EXPECT_EQ(plain_message.size(), encrypted_message.size())
+                << "Encrypt finish returned OK, but did not consume all of the given input";
         cipher_params.push_back(out_params);
 
         EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params));
 
         string decrypted_message;
         rc = Finish(encrypted_message, &decrypted_message);
-
-        if (rc == ErrorCode::OK) {
-            EXPECT_EQ(plain_message.size(), decrypted_message.size())
-                    << "Decrypt finish returned OK, did not consume all of the given input";
-        } else {
-            EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, rc)
-                    << "Encrypt finish failed in an unexpected way when given a large input";
-        }
+        EXPECT_EQ(ErrorCode::OK, rc);
+        EXPECT_EQ(plain_message.size(), decrypted_message.size())
+                << "Decrypt finish returned OK, did not consume all of the given input";
     }
-
-    CheckedDeleteKey();
 }
 
-static const auto kKeymasterDeviceChoices =
-        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor));
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, NewKeyGenerationTest, kKeymasterDeviceChoices,
-                         android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, ImportKeyTest, kKeymasterDeviceChoices,
-                         android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, ImportWrappedKeyTest, kKeymasterDeviceChoices,
-                         android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, SigningOperationsTest, kKeymasterDeviceChoices,
-                         android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, VerificationOperationsTest, kKeymasterDeviceChoices,
-                         android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, ExportKeyTest, kKeymasterDeviceChoices,
-                         android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, EncryptionOperationsTest, kKeymasterDeviceChoices,
-                         android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, MaxOperationsTest, kKeymasterDeviceChoices,
-                         android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, AddEntropyTest, kKeymasterDeviceChoices,
-                         android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, AttestationTest, kKeymasterDeviceChoices,
-                         android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, KeyDeletionTest, kKeymasterDeviceChoices,
-                         android::hardware::PrintInstanceNameToString);
-
-INSTANTIATE_TEST_SUITE_P(PerInstance, TransportLimitTest, kKeymasterDeviceChoices,
-                         android::hardware::PrintInstanceNameToString);
+INSTANTIATE_KEYMASTER_HIDL_TEST(TransportLimitTest);
 
 }  // namespace test
 }  // namespace V4_0
diff --git a/keymaster/4.1/default/Android.bp b/keymaster/4.1/default/Android.bp
index b06878b..27297b9 100644
--- a/keymaster/4.1/default/Android.bp
+++ b/keymaster/4.1/default/Android.bp
@@ -31,6 +31,7 @@
         "libhidlbase",
         "libkeymaster4",
         "libkeymaster41",
+        "libkeymaster4_1support",
         "liblog",
         "libutils",
     ],
diff --git a/keymaster/4.1/support/Android.bp b/keymaster/4.1/support/Android.bp
index 34b6108..bdd0ca8 100644
--- a/keymaster/4.1/support/Android.bp
+++ b/keymaster/4.1/support/Android.bp
@@ -22,11 +22,25 @@
         "-Wextra",
         "-Werror",
     ],
+    srcs: [
+        "attestation_record.cpp",
+        "Keymaster.cpp",
+        "Keymaster3.cpp",
+        "Keymaster4.cpp",
+    ],
     export_include_dirs: ["include"],
     shared_libs: [
         "android.hardware.keymaster@3.0",
         "android.hardware.keymaster@4.0",
         "android.hardware.keymaster@4.1",
+        "libbase",
+        "libcrypto",
+        "libhidlbase",
         "libkeymaster4support",
-    ]
+        "libutils",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.keymaster@4.1",
+        "libkeymaster4support",
+    ],
 }
diff --git a/keymaster/4.0/support/Keymaster.cpp b/keymaster/4.1/support/Keymaster.cpp
similarity index 85%
rename from keymaster/4.0/support/Keymaster.cpp
rename to keymaster/4.1/support/Keymaster.cpp
index f20f951..ea6604e 100644
--- a/keymaster/4.0/support/Keymaster.cpp
+++ b/keymaster/4.1/support/Keymaster.cpp
@@ -14,19 +14,18 @@
  ** limitations under the License.
  */
 
-#include <keymasterV4_0/Keymaster.h>
+#include <keymasterV4_1/Keymaster.h>
 
 #include <iomanip>
 
 #include <android-base/logging.h>
 #include <android/hidl/manager/1.2/IServiceManager.h>
-#include <keymasterV4_0/Keymaster3.h>
-#include <keymasterV4_0/Keymaster4.h>
 #include <keymasterV4_0/key_param_output.h>
 #include <keymasterV4_0/keymaster_utils.h>
+#include <keymasterV4_1/Keymaster3.h>
+#include <keymasterV4_1/Keymaster4.h>
 
-namespace android {
-namespace hardware {
+namespace android::hardware {
 
 template <class T>
 std::ostream& operator<<(std::ostream& os, const hidl_vec<T>& vec) {
@@ -57,6 +56,7 @@
 }
 
 namespace keymaster {
+
 namespace V4_0 {
 
 std::ostream& operator<<(std::ostream& os, const HmacSharingParameters& params) {
@@ -66,7 +66,9 @@
     return os;
 }
 
-namespace support {
+}  // namespace V4_0
+
+namespace V4_1::support {
 
 using ::android::sp;
 using ::android::hidl::manager::V1_2::IServiceManager;
@@ -140,14 +142,14 @@
 }
 
 static hidl_vec<HmacSharingParameters> getHmacParameters(
-    const Keymaster::KeymasterSet& keymasters) {
+        const Keymaster::KeymasterSet& keymasters) {
     std::vector<HmacSharingParameters> params_vec;
     params_vec.reserve(keymasters.size());
     for (auto& keymaster : keymasters) {
         if (keymaster->halVersion().majorVersion < 4) continue;
         auto rc = keymaster->getHmacSharingParameters([&](auto error, auto& params) {
-            CHECK(error == ErrorCode::OK)
-                << "Failed to get HMAC parameters from " << *keymaster << " error " << error;
+            CHECK(error == V4_0::ErrorCode::OK)
+                    << "Failed to get HMAC parameters from " << *keymaster << " error " << error;
             params_vec.push_back(params);
         });
         CHECK(rc.isOk()) << "Failed to communicate with " << *keymaster
@@ -169,18 +171,18 @@
         if (keymaster->halVersion().majorVersion < 4) continue;
         LOG(DEBUG) << "Computing HMAC for " << *keymaster;
         auto rc = keymaster->computeSharedHmac(
-            params, [&](ErrorCode error, const hidl_vec<uint8_t>& curSharingCheck) {
-                CHECK(error == ErrorCode::OK)
-                    << "Failed to get HMAC parameters from " << *keymaster << " error " << error;
-                if (firstKeymaster) {
-                    sharingCheck = curSharingCheck;
-                    firstKeymaster = false;
-                }
-                if (curSharingCheck != sharingCheck)
-                    LOG(WARNING) << "HMAC computation failed for " << *keymaster  //
-                                 << " Expected: " << sharingCheck                 //
-                                 << " got: " << curSharingCheck;
-            });
+                params, [&](V4_0::ErrorCode error, const hidl_vec<uint8_t>& curSharingCheck) {
+                    CHECK(error == V4_0::ErrorCode::OK) << "Failed to get HMAC parameters from "
+                                                        << *keymaster << " error " << error;
+                    if (firstKeymaster) {
+                        sharingCheck = curSharingCheck;
+                        firstKeymaster = false;
+                    }
+                    if (curSharingCheck != sharingCheck)
+                        LOG(WARNING) << "HMAC computation failed for " << *keymaster  //
+                                     << " Expected: " << sharingCheck                 //
+                                     << " got: " << curSharingCheck;
+                });
         CHECK(rc.isOk()) << "Failed to communicate with " << *keymaster
                          << " error: " << rc.description();
     }
@@ -190,8 +192,6 @@
     computeHmac(keymasters, getHmacParameters(keymasters));
 }
 
-}  // namespace support
-}  // namespace V4_0
+}  // namespace V4_1::support
 }  // namespace keymaster
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware
diff --git a/keymaster/4.0/support/Keymaster3.cpp b/keymaster/4.1/support/Keymaster3.cpp
similarity index 81%
rename from keymaster/4.0/support/Keymaster3.cpp
rename to keymaster/4.1/support/Keymaster3.cpp
index b2cdbd9..b665689 100644
--- a/keymaster/4.0/support/Keymaster3.cpp
+++ b/keymaster/4.1/support/Keymaster3.cpp
@@ -15,23 +15,19 @@
  ** limitations under the License.
  */
 
-#include <keymasterV4_0/Keymaster3.h>
+#include <keymasterV4_1/Keymaster3.h>
 
 #include <android-base/logging.h>
 #include <keymasterV4_0/keymaster_utils.h>
 
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
+namespace android::hardware::keymaster::V4_1::support {
 
 using android::hardware::details::StatusOf;
 
 namespace {
 
-ErrorCode convert(V3_0::ErrorCode error) {
-    return static_cast<ErrorCode>(error);
+V4_0::ErrorCode convert(V3_0::ErrorCode error) {
+    return static_cast<V4_0::ErrorCode>(error);
 }
 
 V3_0::KeyPurpose convert(KeyPurpose purpose) {
@@ -53,7 +49,7 @@
 
 KeyParameter convert(const V3_0::KeyParameter& param) {
     KeyParameter converted;
-    converted.tag = static_cast<Tag>(param.tag);
+    converted.tag = static_cast<V4_0::Tag>(param.tag);
     static_assert(sizeof(converted.f) == sizeof(param.f), "This function assumes sizes match");
     memcpy(&converted.f, &param.f, sizeof(param.f));
     converted.blob = param.blob;
@@ -89,7 +85,7 @@
         converted[i] = convert(params[i]);
     }
     converted[params.size()].tag = V3_0::Tag::AUTH_TOKEN;
-    converted[params.size()].blob = authToken2HidlVec(authToken);
+    converted[params.size()].blob = V4_0::support::authToken2HidlVec(authToken);
 
     return converted;
 }
@@ -107,16 +103,19 @@
     if (haveVersion_) return;
 
     auto rc = km3_dev_->getHardwareFeatures(
-        [&](bool isSecure, bool supportsEllipticCurve, bool supportsSymmetricCryptography,
-            bool supportsAttestation, bool supportsAllDigests, const hidl_string& keymasterName,
-            const hidl_string& keymasterAuthorName) {
-            version_ = {keymasterName, keymasterAuthorName, 0 /* major version, filled below */,
-                        isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE,
-                        supportsEllipticCurve};
-            supportsSymmetricCryptography_ = supportsSymmetricCryptography;
-            supportsAttestation_ = supportsAttestation;
-            supportsAllDigests_ = supportsAllDigests;
-        });
+            [&](bool isSecure, bool supportsEllipticCurve, bool supportsSymmetricCryptography,
+                bool supportsAttestation, bool supportsAllDigests, const hidl_string& keymasterName,
+                const hidl_string& keymasterAuthorName) {
+                version_ = {keymasterName,
+                            keymasterAuthorName,
+                            0 /* major version, filled below */,
+                            0 /* minor version */,
+                            isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE,
+                            supportsEllipticCurve};
+                supportsSymmetricCryptography_ = supportsSymmetricCryptography;
+                supportsAttestation_ = supportsAttestation;
+                supportsAllDigests_ = supportsAllDigests;
+            });
 
     CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware features";
 
@@ -139,10 +138,10 @@
     return Void();
 }
 
-Return<ErrorCode> Keymaster3::addRngEntropy(const hidl_vec<uint8_t>& data) {
+Return<V4_0::ErrorCode> Keymaster3::addRngEntropy(const hidl_vec<uint8_t>& data) {
     auto rc = km3_dev_->addRngEntropy(data);
     if (!rc.isOk()) {
-        return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+        return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
     }
     return convert(rc);
 }
@@ -215,21 +214,21 @@
     return rc;
 }
 
-Return<ErrorCode> Keymaster3::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
+Return<V4_0::ErrorCode> Keymaster3::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
     auto rc = km3_dev_->deleteKey(keyBlob);
-    if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+    if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
     return convert(rc);
 }
 
-Return<ErrorCode> Keymaster3::deleteAllKeys() {
+Return<V4_0::ErrorCode> Keymaster3::deleteAllKeys() {
     auto rc = km3_dev_->deleteAllKeys();
-    if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+    if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
     return convert(rc);
 }
 
-Return<ErrorCode> Keymaster3::destroyAttestationIds() {
+Return<V4_0::ErrorCode> Keymaster3::destroyAttestationIds() {
     auto rc = km3_dev_->destroyAttestationIds();
-    if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+    if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
     return convert(rc);
 }
 
@@ -242,7 +241,7 @@
     };
 
     auto rc =
-        km3_dev_->begin(convert(purpose), key, convertAndAddAuthToken(inParams, authToken), cb);
+            km3_dev_->begin(convert(purpose), key, convertAndAddAuthToken(inParams, authToken), cb);
     rc.isOk();  // move ctor prereq
     return rc;
 }
@@ -256,8 +255,8 @@
         _hidl_cb(convert(error), inputConsumed, convert(outParams), output);
     };
 
-    auto rc =
-        km3_dev_->update(operationHandle, convertAndAddAuthToken(inParams, authToken), input, cb);
+    auto rc = km3_dev_->update(operationHandle, convertAndAddAuthToken(inParams, authToken), input,
+                               cb);
     rc.isOk();  // move ctor prereq
     return rc;
 }
@@ -278,14 +277,10 @@
     return rc;
 }
 
-Return<ErrorCode> Keymaster3::abort(uint64_t operationHandle) {
+Return<V4_0::ErrorCode> Keymaster3::abort(uint64_t operationHandle) {
     auto rc = km3_dev_->abort(operationHandle);
-    if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+    if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, V4_0::ErrorCode>(rc);
     return convert(rc);
 }
 
-}  // namespace support
-}  // namespace V4_0
-}  // namespace keymaster
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/Keymaster4.cpp b/keymaster/4.1/support/Keymaster4.cpp
new file mode 100644
index 0000000..33f4bb1
--- /dev/null
+++ b/keymaster/4.1/support/Keymaster4.cpp
@@ -0,0 +1,41 @@
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <keymasterV4_1/Keymaster4.h>
+
+#include <android-base/logging.h>
+
+namespace android::hardware::keymaster::V4_1::support {
+
+void Keymaster4::getVersionIfNeeded() {
+    if (haveVersion_) return;
+
+    auto rc = km4_0_dev_->getHardwareInfo([&](SecurityLevel securityLevel,
+                                              const hidl_string& keymasterName,
+                                              const hidl_string& authorName) {
+        version_ = {keymasterName,
+                    authorName,
+                    4 /* major version */,
+                    static_cast<uint8_t>((km4_1_dev_) ? 1 : 0) /* minor version */,
+                    securityLevel,
+                    true /* supportsEc */};
+        haveVersion_ = true;
+    });
+
+    CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware info";
+}
+
+}  // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/OWNERS b/keymaster/4.1/support/OWNERS
new file mode 100644
index 0000000..a9efe66
--- /dev/null
+++ b/keymaster/4.1/support/OWNERS
@@ -0,0 +1,3 @@
+jdanis@google.com
+swillden@google.com
+jbires@google.com
diff --git a/keymaster/4.1/support/attestation_record.cpp b/keymaster/4.1/support/attestation_record.cpp
new file mode 100644
index 0000000..9eab1db
--- /dev/null
+++ b/keymaster/4.1/support/attestation_record.cpp
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keymasterV4_1/attestation_record.h>
+
+#include <android-base/logging.h>
+#include <assert.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <keymasterV4_0/authorization_set.h>
+#include <keymasterV4_0/openssl_utils.h>
+
+#define AT __FILE__ ":" << __LINE__
+
+/*
+ * NOTE: The contents of this file are *extremely* similar to the contents of the V4_0 copy of the
+ * same support file.  Unfortunately, small changes in the scheme mean that the schema types have to
+ * be distinct, which drives almost everything else to be different as well.  In the next version we
+ * plan to abandon not just this openssl mechanism for parsing ASN.1, but ASN.1 entirely, so
+ * eventually all of this duplication can be removed.
+ */
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_1 {
+
+struct stack_st_ASN1_TYPE_Delete {
+    void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); }
+};
+
+struct ASN1_STRING_Delete {
+    void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); }
+};
+
+struct ASN1_TYPE_Delete {
+    void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); }
+};
+
+#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER)
+
+typedef struct km_root_of_trust {
+    ASN1_OCTET_STRING* verified_boot_key;
+    ASN1_BOOLEAN* device_locked;
+    ASN1_ENUMERATED* verified_boot_state;
+    ASN1_OCTET_STRING* verified_boot_hash;
+} KM_ROOT_OF_TRUST;
+
+ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = {
+        ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING),
+        ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN),
+        ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED),
+        ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_hash, ASN1_OCTET_STRING),
+} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
+
+typedef struct km_auth_list {
+    ASN1_INTEGER_SET* purpose;
+    ASN1_INTEGER* algorithm;
+    ASN1_INTEGER* key_size;
+    ASN1_INTEGER_SET* digest;
+    ASN1_INTEGER_SET* padding;
+    ASN1_INTEGER* ec_curve;
+    ASN1_INTEGER* rsa_public_exponent;
+    ASN1_INTEGER* active_date_time;
+    ASN1_INTEGER* origination_expire_date_time;
+    ASN1_INTEGER* usage_expire_date_time;
+    ASN1_NULL* no_auth_required;
+    ASN1_INTEGER* user_auth_type;
+    ASN1_INTEGER* auth_timeout;
+    ASN1_NULL* allow_while_on_body;
+    ASN1_NULL* all_applications;
+    ASN1_OCTET_STRING* application_id;
+    ASN1_INTEGER* creation_date_time;
+    ASN1_INTEGER* origin;
+    ASN1_NULL* rollback_resistance;
+    KM_ROOT_OF_TRUST* root_of_trust;
+    ASN1_INTEGER* os_version;
+    ASN1_INTEGER* os_patchlevel;
+    ASN1_OCTET_STRING* attestation_application_id;
+    ASN1_NULL* trusted_user_presence_required;
+    ASN1_NULL* trusted_confirmation_required;
+    ASN1_NULL* unlocked_device_required;
+    ASN1_INTEGER* vendor_patchlevel;
+    ASN1_INTEGER* boot_patchlevel;
+    ASN1_NULL* early_boot_only;
+    ASN1_NULL* device_unique_attestation;
+} KM_AUTH_LIST;
+
+ASN1_SEQUENCE(KM_AUTH_LIST) = {
+        ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.maskedTag()),
+        ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.maskedTag()),
+        ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
+                     TAG_RSA_PUBLIC_EXPONENT.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL,
+                     TAG_ROLLBACK_RESISTANCE.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
+                     TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
+                     TAG_USAGE_EXPIRE_DATETIME.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL,
+                     TAG_ALLOW_WHILE_ON_BODY.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, trusted_user_presence_required, ASN1_NULL,
+                     TAG_TRUSTED_USER_PRESENCE_REQUIRED.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, trusted_confirmation_required, ASN1_NULL,
+                     TAG_TRUSTED_CONFIRMATION_REQUIRED.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, unlocked_device_required, ASN1_NULL,
+                     TAG_UNLOCKED_DEVICE_REQUIRED.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER,
+                     TAG_CREATION_DATETIME.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER,
+                     TAG_VENDOR_PATCHLEVEL.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, boot_patchlevel, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, device_unique_attestation, ASN1_NULL,
+                     TAG_DEVICE_UNIQUE_ATTESTATION.maskedTag()),
+} ASN1_SEQUENCE_END(KM_AUTH_LIST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
+
+typedef struct km_key_description {
+    ASN1_INTEGER* attestation_version;
+    ASN1_ENUMERATED* attestation_security_level;
+    ASN1_INTEGER* keymaster_version;
+    ASN1_ENUMERATED* keymaster_security_level;
+    ASN1_OCTET_STRING* attestation_challenge;
+    KM_AUTH_LIST* software_enforced;
+    KM_AUTH_LIST* tee_enforced;
+    ASN1_INTEGER* unique_id;
+} KM_KEY_DESCRIPTION;
+
+ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = {
+        ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_version, ASN1_INTEGER),
+        ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_security_level, ASN1_ENUMERATED),
+        ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_version, ASN1_INTEGER),
+        ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_security_level, ASN1_ENUMERATED),
+        ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_challenge, ASN1_OCTET_STRING),
+        ASN1_SIMPLE(KM_KEY_DESCRIPTION, unique_id, ASN1_OCTET_STRING),
+        ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST),
+        ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST),
+} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION);
+IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION);
+
+template <V4_0::Tag tag>
+void copyAuthTag(const stack_st_ASN1_INTEGER* stack, TypedTag<TagType::ENUM_REP, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    typedef typename V4_0::TypedTag2ValueType<decltype(ttag)>::type ValueT;
+    for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) {
+        auth_list->push_back(
+                ttag, static_cast<ValueT>(ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i))));
+    }
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ENUM, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    typedef typename V4_0::TypedTag2ValueType<decltype(ttag)>::type ValueT;
+    if (!asn1_int) return;
+    auth_list->push_back(ttag, static_cast<ValueT>(ASN1_INTEGER_get(asn1_int)));
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::UINT, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_int) return;
+    auth_list->push_back(ttag, ASN1_INTEGER_get(asn1_int));
+}
+
+BIGNUM* construct_uint_max() {
+    BIGNUM* value = BN_new();
+    BIGNUM_Ptr one(BN_new());
+    BN_one(one.get());
+    BN_lshift(value, one.get(), 32);
+    return value;
+}
+
+uint64_t BignumToUint64(BIGNUM* num) {
+    static_assert((sizeof(BN_ULONG) == sizeof(uint32_t)) || (sizeof(BN_ULONG) == sizeof(uint64_t)),
+                  "This implementation only supports 32 and 64-bit BN_ULONG");
+    if (sizeof(BN_ULONG) == sizeof(uint32_t)) {
+        BIGNUM_Ptr uint_max(construct_uint_max());
+        BIGNUM_Ptr hi(BN_new()), lo(BN_new());
+        BN_CTX_Ptr ctx(BN_CTX_new());
+        BN_div(hi.get(), lo.get(), num, uint_max.get(), ctx.get());
+        return static_cast<uint64_t>(BN_get_word(hi.get())) << 32 | BN_get_word(lo.get());
+    } else if (sizeof(BN_ULONG) == sizeof(uint64_t)) {
+        return BN_get_word(num);
+    } else {
+        return 0;
+    }
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ULONG, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_int) return;
+    BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+    auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::DATE, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_int) return;
+    BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+    auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_NULL* asn1_null, TypedTag<TagType::BOOL, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_null) return;
+    auth_list->push_back(ttag);
+}
+
+template <V4_0::Tag tag>
+void copyAuthTag(const ASN1_OCTET_STRING* asn1_string, TypedTag<TagType::BYTES, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_string) return;
+    hidl_vec<uint8_t> buf;
+    buf.setToExternal(asn1_string->data, asn1_string->length);
+    auth_list->push_back(ttag, buf);
+}
+
+// Extract the values from the specified ASN.1 record and place them in auth_list.
+static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* auth_list) {
+    if (!record) return ErrorCode::OK;
+
+    copyAuthTag(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list);
+    copyAuthTag(record->algorithm, TAG_ALGORITHM, auth_list);
+    copyAuthTag(record->application_id, TAG_APPLICATION_ID, auth_list);
+    copyAuthTag(record->auth_timeout, TAG_AUTH_TIMEOUT, auth_list);
+    copyAuthTag(record->creation_date_time, TAG_CREATION_DATETIME, auth_list);
+    copyAuthTag(record->digest, TAG_DIGEST, auth_list);
+    copyAuthTag(record->ec_curve, TAG_EC_CURVE, auth_list);
+    copyAuthTag(record->key_size, TAG_KEY_SIZE, auth_list);
+    copyAuthTag(record->no_auth_required, TAG_NO_AUTH_REQUIRED, auth_list);
+    copyAuthTag(record->origin, TAG_ORIGIN, auth_list);
+    copyAuthTag(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, auth_list);
+    copyAuthTag(record->os_patchlevel, TAG_OS_PATCHLEVEL, auth_list);
+    copyAuthTag(record->os_version, TAG_OS_VERSION, auth_list);
+    copyAuthTag(record->padding, TAG_PADDING, auth_list);
+    copyAuthTag(record->purpose, TAG_PURPOSE, auth_list);
+    copyAuthTag(record->rollback_resistance, TAG_ROLLBACK_RESISTANCE, auth_list);
+    copyAuthTag(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list);
+    copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list);
+    copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list);
+    copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list);
+    copyAuthTag(record->vendor_patchlevel, TAG_VENDOR_PATCHLEVEL, auth_list);
+    copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list);
+    copyAuthTag(record->trusted_user_presence_required, TAG_TRUSTED_USER_PRESENCE_REQUIRED,
+                auth_list);
+    copyAuthTag(record->trusted_confirmation_required, TAG_TRUSTED_CONFIRMATION_REQUIRED,
+                auth_list);
+    copyAuthTag(record->unlocked_device_required, TAG_UNLOCKED_DEVICE_REQUIRED, auth_list);
+    copyAuthTag(record->early_boot_only, TAG_EARLY_BOOT_ONLY, auth_list);
+    copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list);
+
+    return ErrorCode::OK;
+}
+
+MAKE_OPENSSL_PTR_TYPE(KM_KEY_DESCRIPTION)
+
+// Parse the DER-encoded attestation record, placing the results in keymaster_version,
+// attestation_challenge, software_enforced, tee_enforced and unique_id.
+std::tuple<ErrorCode, AttestationRecord> parse_attestation_record(const hidl_vec<uint8_t>& cert) {
+    const uint8_t* p = cert.data();
+    X509_Ptr x509(d2i_X509(nullptr, &p, cert.size()));
+
+    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+    if (!oid.get()) {
+        LOG(ERROR) << "Error parsing OID";
+        return {ErrorCode::UNKNOWN_ERROR, {}};
+    }
+
+    int location = X509_get_ext_by_OBJ(x509.get(), oid.get(), -1 /* search from beginning */);
+    if (location == -1) {
+        LOG(ERROR) << "Attestation extension not found in certificate";
+        return {ErrorCode::UNKNOWN_ERROR, {}};
+    }
+
+    X509_EXTENSION* attest_rec_ext = X509_get_ext(x509.get(), location);
+    if (!attest_rec_ext) {
+        LOG(ERROR) << "Found extension but couldn't retrieve it.  Probably BoringSSL bug.";
+        return {ErrorCode::UNKNOWN_ERROR, {}};
+    }
+
+    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+    if (!attest_rec_ext) {
+        LOG(ERROR) << "Attestation extension contained no data";
+        return {ErrorCode::UNKNOWN_ERROR, {}};
+    }
+
+    p = attest_rec->data;
+    KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, attest_rec->length));
+    if (!record.get()) return {ErrorCode::UNKNOWN_ERROR, {}};
+
+    AttestationRecord result;
+
+    result.attestation_version = ASN1_INTEGER_get(record->attestation_version);
+    result.attestation_security_level =
+            static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->attestation_security_level));
+    result.keymaster_version = ASN1_INTEGER_get(record->keymaster_version);
+    result.keymaster_security_level =
+            static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->keymaster_security_level));
+
+    auto& chall = record->attestation_challenge;
+    result.attestation_challenge.resize(chall->length);
+    memcpy(result.attestation_challenge.data(), chall->data, chall->length);
+    auto& uid = record->unique_id;
+    result.unique_id.resize(uid->length);
+    memcpy(result.unique_id.data(), uid->data, uid->length);
+
+    ErrorCode error = extract_auth_list(record->software_enforced, &result.software_enforced);
+    if (error != ErrorCode::OK) return {error, {}};
+
+    error = extract_auth_list(record->tee_enforced, &result.hardware_enforced);
+    if (error != ErrorCode::OK) return {error, {}};
+
+    KM_ROOT_OF_TRUST* root_of_trust = nullptr;
+    if (record->tee_enforced && record->tee_enforced->root_of_trust) {
+        root_of_trust = record->tee_enforced->root_of_trust;
+    } else if (record->software_enforced && record->software_enforced->root_of_trust) {
+        root_of_trust = record->software_enforced->root_of_trust;
+    } else {
+        LOG(ERROR) << AT << " Failed root of trust parsing";
+        return {ErrorCode::INVALID_ARGUMENT, {}};
+    }
+    if (!root_of_trust->verified_boot_key) {
+        LOG(ERROR) << AT << " Failed verified boot key parsing";
+        return {ErrorCode::INVALID_ARGUMENT, {}};
+    }
+
+    RootOfTrust& rot = result.root_of_trust;
+    auto& vb_key = root_of_trust->verified_boot_key;
+    rot.verified_boot_key.resize(vb_key->length);
+    memcpy(rot.verified_boot_key.data(), vb_key->data, vb_key->length);
+
+    rot.verified_boot_state = static_cast<keymaster_verified_boot_t>(
+            ASN1_ENUMERATED_get(root_of_trust->verified_boot_state));
+    rot.device_locked = root_of_trust->device_locked;
+
+    auto& vb_hash = root_of_trust->verified_boot_hash;
+    if (!vb_hash) {
+        LOG(ERROR) << AT << " Failed verified boot hash parsing";
+        return {ErrorCode::INVALID_ARGUMENT, {}};
+    }
+    rot.verified_boot_hash.resize(vb_hash->length);
+    memcpy(rot.verified_boot_hash.data(), vb_hash->data, vb_hash->length);
+
+    return {ErrorCode::OK, result};
+}
+
+}  // namespace V4_1
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster.h
similarity index 73%
rename from keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
rename to keymaster/4.1/support/include/keymasterV4_1/Keymaster.h
index ad83f17..1f49e18 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster.h
@@ -15,28 +15,28 @@
  ** limitations under the License.
  */
 
-#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
-#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
-
-#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
+#pragma once
 
 #include <memory>
 #include <vector>
 
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
+#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
+#include <keymasterV4_1/keymaster_tags.h>
+
+namespace android::hardware::keymaster::V4_1::support {
 
 /**
- * Keymaster abstracts the underlying V4_0::IKeymasterDevice.  There is one implementation
- * (Keymaster4) which is a trivial passthrough and one that wraps a V3_0::IKeymasterDevice.
+ * Keymaster abstracts the underlying V4_1::IKeymasterDevice.  There are two implementations,
+ * Keymaster3 which wraps a V3_0::IKeymasterDevice and Keymaster4, which wraps either a
+ * V4_0::IKeymasterDevice or a V4_1::IKeymasterDevice.  There is a V3_0::IKeymasterDevice
+ * implementation that is used to wrap pre-HIDL keymaster implementations, and Keymaster3 will wrap
+ * that.
  *
  * The reason for adding this additional layer, rather than simply using the latest HAL directly and
  * subclassing it to wrap any older HAL, is because this provides a place to put additional methods
  * which clients can use when they need to distinguish between different underlying HAL versions,
- * while still having to use only the latest interface.
+ * while still having to use only the latest interface.  Plus it's a handy place to keep some
+ * convenience methods.
  */
 class Keymaster : public IKeymasterDevice {
   public:
@@ -50,12 +50,14 @@
         hidl_string keymasterName;
         hidl_string authorName;
         uint8_t majorVersion;
+        uint8_t minorVersion;
         SecurityLevel securityLevel;
         bool supportsEc;
 
         bool operator>(const VersionResult& other) const {
-            auto lhs = std::tie(securityLevel, majorVersion, supportsEc);
-            auto rhs = std::tie(other.securityLevel, other.majorVersion, other.supportsEc);
+            auto lhs = std::tie(securityLevel, majorVersion, minorVersion, supportsEc);
+            auto rhs = std::tie(other.securityLevel, other.majorVersion, other.minorVersion,
+                                other.supportsEc);
             return lhs > rhs;
         }
     };
@@ -69,6 +71,9 @@
      * There are no side effects otherwise.
      */
     void logIfKeymasterVendorError(ErrorCode ec) const;
+    void logIfKeymasterVendorError(V4_0::ErrorCode ec) const {
+        logIfKeymasterVendorError(static_cast<ErrorCode>(ec));
+    }
 
     /**
      * Returns all available Keymaster3 and Keymaster4 instances, in order of most secure to least
@@ -93,10 +98,4 @@
 
 std::ostream& operator<<(std::ostream& os, const Keymaster& keymaster);
 
-}  // namespace support
-}  // namespace V4_0
-}  // namespace keymaster
-}  // namespace hardware
-}  // namespace android
-
-#endif  // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
+}  // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h
similarity index 72%
rename from keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
rename to keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h
index c40be7c..c201e8c 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster3.h
@@ -1,5 +1,4 @@
 /*
- **
  ** Copyright 2017, The Android Open Source Project
  **
  ** Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,18 +14,14 @@
  ** limitations under the License.
  */
 
-#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
-#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
+#pragma once
 
 #include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
 
 #include "Keymaster.h"
+#include "Operation.h"
 
-namespace android {
-namespace hardware {
-namespace keymaster {
-namespace V4_0 {
-namespace support {
+namespace android::hardware::keymaster::V4_1::support {
 
 using IKeymaster3Device = ::android::hardware::keymaster::V3_0::IKeymasterDevice;
 
@@ -38,8 +33,10 @@
 using ::android::hardware::details::return_status;
 
 class Keymaster3 : public Keymaster {
-   public:
+  public:
+    // This definition is used for device enumeration.
     using WrappedIKeymasterDevice = IKeymaster3Device;
+
     Keymaster3(sp<IKeymaster3Device> km3_dev, const hidl_string& instanceName)
         : Keymaster(IKeymaster3Device::descriptor, instanceName),
           km3_dev_(km3_dev),
@@ -53,24 +50,24 @@
     Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb);
 
     Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
-        _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+        _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {});
         return Void();
     }
 
     Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>&,
                                    computeSharedHmac_cb _hidl_cb) override {
-        _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+        _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {});
         return Void();
     }
 
     Return<void> verifyAuthorization(uint64_t, const hidl_vec<KeyParameter>&,
                                      const HardwareAuthToken&,
                                      verifyAuthorization_cb _hidl_cb) override {
-        _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+        _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {});
         return Void();
     }
 
-    Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override;
+    Return<V4_0::ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override;
     Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
                              generateKey_cb _hidl_cb) override;
     Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
@@ -86,7 +83,7 @@
                                   const hidl_vec<KeyParameter>& /* unwrappingParams */,
                                   uint64_t /* passwordSid */, uint64_t /* biometricSid */,
                                   importWrappedKey_cb _hidl_cb) {
-        _hidl_cb(ErrorCode::UNIMPLEMENTED, {}, {});
+        _hidl_cb(V4_0::ErrorCode::UNIMPLEMENTED, {}, {});
         return Void();
     }
 
@@ -99,9 +96,9 @@
     Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
                             const hidl_vec<KeyParameter>& upgradeParams,
                             upgradeKey_cb _hidl_cb) override;
-    Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override;
-    Return<ErrorCode> deleteAllKeys() override;
-    Return<ErrorCode> destroyAttestationIds() override;
+    Return<V4_0::ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override;
+    Return<V4_0::ErrorCode> deleteAllKeys() override;
+    Return<V4_0::ErrorCode> destroyAttestationIds() override;
     Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
                        const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
                        begin_cb _hidl_cb) override;
@@ -112,9 +109,31 @@
                         const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
                         const HardwareAuthToken& authToken,
                         const VerificationToken& verificationToken, finish_cb _hidl_cb) override;
-    Return<ErrorCode> abort(uint64_t operationHandle) override;
+    Return<V4_0::ErrorCode> abort(uint64_t operationHandle) override;
 
-   private:
+    /**********************************
+     * V4_1::IKeymasterDevice methods *
+     *********************************/
+
+    Return<ErrorCode> deviceLocked(bool /* passwordOnly */,
+                                   const VerificationToken& /* verificationToken */) override {
+        return ErrorCode::UNIMPLEMENTED;
+    }
+
+    Return<ErrorCode> earlyBootEnded() override { return ErrorCode::UNIMPLEMENTED; }
+
+    Return<void> beginOp(KeyPurpose purpose, const hidl_vec<uint8_t>& keyBlob,
+                         const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+                         beginOp_cb _hidl_cb) override {
+        return begin(purpose, keyBlob, inParams, authToken,
+                     [&_hidl_cb](V4_0::ErrorCode errorCode, const hidl_vec<KeyParameter>& outParams,
+                                 OperationHandle operationHandle) {
+                         _hidl_cb(static_cast<ErrorCode>(errorCode), outParams,
+                                  new Operation(operationHandle));
+                     });
+    }
+
+  private:
     void getVersionIfNeeded();
 
     sp<IKeymaster3Device> km3_dev_;
@@ -126,10 +145,4 @@
     bool supportsAllDigests_;
 };
 
-}  // namespace support
-}  // namespace V4_0
-}  // namespace keymaster
-}  // namespace hardware
-}  // namespace android
-
-#endif  // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
+}  // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h b/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h
new file mode 100644
index 0000000..6d74d98
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/Keymaster4.h
@@ -0,0 +1,197 @@
+/*
+ ** Copyright 2020, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#pragma once
+
+#include "Keymaster.h"
+#include "Operation.h"
+
+namespace android::hardware::keymaster::V4_1::support {
+
+using android::sp;
+
+/**
+ * This class can wrap either a V4_0 or V4_1 IKeymasterDevice.
+ */
+class Keymaster4 : public Keymaster {
+  public:
+    // This definition is used for device enumeration; enumerating 4.0 devices will also
+    // enumerate 4.1. devices.
+    using WrappedIKeymasterDevice = V4_0::IKeymasterDevice;
+
+    Keymaster4(sp<V4_1::IKeymasterDevice> km4_1_dev, const hidl_string& instanceName)
+        : Keymaster(V4_1::IKeymasterDevice::descriptor, instanceName),
+          haveVersion_(false),
+          km4_0_dev_(km4_1_dev),
+          km4_1_dev_(km4_1_dev) {}
+
+    Keymaster4(sp<V4_0::IKeymasterDevice> km4_0_dev, const hidl_string& instanceName)
+        : Keymaster(V4_1::IKeymasterDevice::descriptor, instanceName),
+          haveVersion_(false),
+          km4_0_dev_(km4_0_dev),
+          km4_1_dev_() {}
+
+    const VersionResult& halVersion() const override {
+        const_cast<Keymaster4*>(this)->getVersionIfNeeded();
+        return version_;
+    }
+
+    /**********************************
+     * V4_0::IKeymasterDevice methods *
+     *********************************/
+
+    Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb) override {
+        return km4_0_dev_->getHardwareInfo(_hidl_cb);
+    }
+
+    Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
+        return km4_0_dev_->getHmacSharingParameters(_hidl_cb);
+    }
+
+    Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>& params,
+                                   computeSharedHmac_cb _hidl_cb) override {
+        return km4_0_dev_->computeSharedHmac(params, _hidl_cb);
+    }
+
+    Return<void> verifyAuthorization(uint64_t operationHandle, const hidl_vec<KeyParameter>& params,
+                                     const HardwareAuthToken& authToken,
+                                     verifyAuthorization_cb _hidl_cb) override {
+        return km4_0_dev_->verifyAuthorization(operationHandle, params, authToken, _hidl_cb);
+    }
+
+    Return<V4_0::ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override {
+        return km4_0_dev_->addRngEntropy(data);
+    }
+
+    Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
+                             generateKey_cb _hidl_cb) override {
+        return km4_0_dev_->generateKey(keyParams, _hidl_cb);
+    }
+
+    Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+                                       const hidl_vec<uint8_t>& clientId,
+                                       const hidl_vec<uint8_t>& appData,
+                                       getKeyCharacteristics_cb _hidl_cb) override {
+        return km4_0_dev_->getKeyCharacteristics(keyBlob, clientId, appData, _hidl_cb);
+    }
+
+    Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+                           const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override {
+        return km4_0_dev_->importKey(params, keyFormat, keyData, _hidl_cb);
+    }
+
+    Return<void> importWrappedKey(const hidl_vec<uint8_t>& wrappedKeyData,
+                                  const hidl_vec<uint8_t>& wrappingKeyBlob,
+                                  const hidl_vec<uint8_t>& maskingKey,
+                                  const hidl_vec<KeyParameter>& unwrappingParams,
+                                  uint64_t passwordSid, uint64_t biometricSid,
+                                  importWrappedKey_cb _hidl_cb) {
+        return km4_0_dev_->importWrappedKey(wrappedKeyData, wrappingKeyBlob, maskingKey,
+                                            unwrappingParams, passwordSid, biometricSid, _hidl_cb);
+    }
+
+    Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+                           const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+                           exportKey_cb _hidl_cb) override {
+        return km4_0_dev_->exportKey(exportFormat, keyBlob, clientId, appData, _hidl_cb);
+    }
+
+    Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
+                           const hidl_vec<KeyParameter>& attestParams,
+                           attestKey_cb _hidl_cb) override {
+        return km4_0_dev_->attestKey(keyToAttest, attestParams, _hidl_cb);
+    }
+
+    Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+                            const hidl_vec<KeyParameter>& upgradeParams,
+                            upgradeKey_cb _hidl_cb) override {
+        return km4_0_dev_->upgradeKey(keyBlobToUpgrade, upgradeParams, _hidl_cb);
+    }
+
+    Return<V4_0::ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override {
+        return km4_0_dev_->deleteKey(keyBlob);
+    }
+
+    Return<V4_0::ErrorCode> deleteAllKeys() override { return km4_0_dev_->deleteAllKeys(); }
+
+    Return<V4_0::ErrorCode> destroyAttestationIds() override {
+        return km4_0_dev_->destroyAttestationIds();
+    }
+
+    Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+                       const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+                       begin_cb _hidl_cb) override {
+        return km4_0_dev_->begin(purpose, key, inParams, authToken, _hidl_cb);
+    }
+
+    Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                        const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
+                        const VerificationToken& verificationToken, update_cb _hidl_cb) override {
+        return km4_0_dev_->update(operationHandle, inParams, input, authToken, verificationToken,
+                                  _hidl_cb);
+    }
+
+    Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                        const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+                        const HardwareAuthToken& authToken,
+                        const VerificationToken& verificationToken, finish_cb _hidl_cb) override {
+        return km4_0_dev_->finish(operationHandle, inParams, input, signature, authToken,
+                                  verificationToken, _hidl_cb);
+    }
+
+    Return<V4_0::ErrorCode> abort(uint64_t operationHandle) override {
+        return km4_0_dev_->abort(operationHandle);
+    }
+
+    /**********************************
+     * V4_1::IKeymasterDevice methods *
+     *********************************/
+
+    Return<ErrorCode> deviceLocked(bool passwordOnly,
+                                   const VerificationToken& verificationToken) override {
+        if (km4_1_dev_) return km4_1_dev_->deviceLocked(passwordOnly, verificationToken);
+        return ErrorCode::UNIMPLEMENTED;
+    }
+
+    Return<ErrorCode> earlyBootEnded() override {
+        if (km4_1_dev_) return km4_1_dev_->earlyBootEnded();
+        return ErrorCode::UNIMPLEMENTED;
+    }
+
+    Return<void> beginOp(KeyPurpose purpose, const hidl_vec<uint8_t>& keyBlob,
+                         const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+                         beginOp_cb _hidl_cb) override {
+        if (km4_1_dev_) return km4_1_dev_->beginOp(purpose, keyBlob, inParams, authToken, _hidl_cb);
+
+        return km4_0_dev_->begin(
+                purpose, keyBlob, inParams, authToken,
+                [&_hidl_cb](V4_0::ErrorCode errorCode, const hidl_vec<KeyParameter>& outParams,
+                            OperationHandle operationHandle) {
+                    _hidl_cb(static_cast<ErrorCode>(errorCode), outParams,
+                             new Operation(operationHandle));
+                });
+    }
+
+  private:
+    void getVersionIfNeeded();
+
+    bool haveVersion_;
+    VersionResult version_;
+    sp<V4_0::IKeymasterDevice> km4_0_dev_;
+    sp<V4_1::IKeymasterDevice> km4_1_dev_;
+};  // namespace android::hardware::keymaster::V4_1::support
+
+}  // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/include/keymasterV4_1/Operation.h b/keymaster/4.1/support/include/keymasterV4_1/Operation.h
new file mode 100644
index 0000000..902d49a
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/Operation.h
@@ -0,0 +1,38 @@
+/*
+ ** Copyright 2020, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/keymaster/4.1/IOperation.h>
+
+#include <keymasterV4_1/keymaster_tags.h>
+
+namespace android::hardware::keymaster::V4_1::support {
+
+class Operation : public IOperation {
+  public:
+    Operation(OperationHandle handle) : handle_(handle) {}
+
+    Return<void> getOperationChallenge(getOperationChallenge_cb _hidl_cb) override {
+        _hidl_cb(V4_1::ErrorCode::OK, handle_);
+        return Void();
+    }
+
+  private:
+    OperationHandle handle_;
+};
+
+}  // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/support/include/keymasterV4_1/attestation_record.h b/keymaster/4.1/support/include/keymasterV4_1/attestation_record.h
new file mode 100644
index 0000000..b543bdd
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/attestation_record.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
+#include <keymasterV4_0/attestation_record.h>
+#include <keymasterV4_0/openssl_utils.h>
+#include <keymasterV4_1/authorization_set.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_1 {
+
+using V4_0::kAttestionRecordOid;
+using V4_0::keymaster_verified_boot_t;
+
+struct RootOfTrust {
+    SecurityLevel security_level;
+    hidl_vec<uint8_t> verified_boot_key;
+    hidl_vec<uint8_t> verified_boot_hash;
+    keymaster_verified_boot_t verified_boot_state;
+    bool device_locked;
+};
+
+struct AttestationRecord {
+    RootOfTrust root_of_trust;
+    uint32_t attestation_version;
+    SecurityLevel attestation_security_level;
+    uint32_t keymaster_version;
+    SecurityLevel keymaster_security_level;
+    hidl_vec<uint8_t> attestation_challenge;
+    AuthorizationSet software_enforced;
+    AuthorizationSet hardware_enforced;
+    hidl_vec<uint8_t> unique_id;
+};
+
+std::tuple<ErrorCode, AttestationRecord> parse_attestation_record(const hidl_vec<uint8_t>& cert);
+
+}  // namespace V4_1
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h b/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h
index afc0eaf..01605b7 100644
--- a/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/authorization_set.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
-#define HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
+#pragma once
 
 #include <keymasterV4_0/authorization_set.h>
 
@@ -28,5 +27,3 @@
 using V4_0::KeyParameter;
 
 }  // namespace android::hardware::keymaster::V4_1
-
-#endif  // HARDWARE_INTERFACES_KEYMASTER_V4_1_SUPPORT_INCLUDE_AUTHORIZATION_SET_H_
diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
index 6ffe8e1..c5ce950 100644
--- a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
@@ -23,16 +23,26 @@
 
 namespace android::hardware::keymaster::V4_1 {
 
+using V4_0::Algorithm;
 using V4_0::BlockMode;
 using V4_0::Digest;
 using V4_0::EcCurve;
-using V4_0::ErrorCode;
+using V4_0::HardwareAuthenticatorType;
 using V4_0::HardwareAuthToken;
+using V4_0::HmacSharingParameters;
+using V4_0::KeyBlobUsageRequirements;
+using V4_0::KeyCharacteristics;
+using V4_0::KeyFormat;
+using V4_0::KeyOrigin;
 using V4_0::KeyParameter;
+using V4_0::KeyPurpose;
+using V4_0::OperationHandle;
 using V4_0::PaddingMode;
+using V4_0::SecurityLevel;
 using V4_0::TagType;
 using V4_0::VerificationToken;
 
+using V4_0::NullOr;
 using V4_0::TypedTag;
 
 using V4_0::TAG_ACTIVE_DATETIME;
diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_utils.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_utils.h
new file mode 100644
index 0000000..2e28002
--- /dev/null
+++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_utils.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <keymasterV4_0/keymaster_utils.h>
+
+namespace android::hardware::keymaster::V4_1::support {
+
+using V4_0::support::blob2hidlVec;
+using V4_0::support::hidlVec2AuthToken;
+
+}  // namespace android::hardware::keymaster::V4_1::support
diff --git a/keymaster/4.1/vts/functional/Android.bp b/keymaster/4.1/vts/functional/Android.bp
index f5a0c9c..c2d7fa3 100644
--- a/keymaster/4.1/vts/functional/Android.bp
+++ b/keymaster/4.1/vts/functional/Android.bp
@@ -19,12 +19,24 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "EarlyBootKeyTest.cpp",
+        "DeviceUniqueAttestationTest.cpp",
+        "Keymaster4_1HidlTest.cpp",
+        "UnlockedDeviceRequiredTest.cpp",
     ],
     static_libs: [
         "android.hardware.keymaster@4.0",
         "android.hardware.keymaster@4.1",
-        "libkeymaster4support",
+        "libcrypto_static",
         "libkeymaster4_1support",
+        "libkeymaster4support",
+        "libkeymaster4vtstest",
     ],
-    test_suites: ["vts-core"],
+    cflags: [
+        "-Wall",
+        "-O0",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
diff --git a/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
new file mode 100644
index 0000000..7ea3275
--- /dev/null
+++ b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Keymaster4_1HidlTest.h"
+
+#include <cutils/properties.h>
+
+#include <openssl/x509.h>
+
+#include <keymasterV4_1/attestation_record.h>
+#include <keymasterV4_1/authorization_set.h>
+
+namespace android::hardware::keymaster::V4_0 {
+
+bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) {
+    return std::equal(a.begin(), a.end(), b.begin(), b.end());
+}
+
+}  // namespace android::hardware::keymaster::V4_0
+
+namespace android::hardware::keymaster::V4_1 {
+
+inline ::std::ostream& operator<<(::std::ostream& os, Tag tag) {
+    return os << toString(tag);
+}
+
+namespace test {
+
+using std::string;
+using std::tuple;
+
+namespace {
+
+char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+                       '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+string bin2hex(const hidl_vec<uint8_t>& data) {
+    string retval;
+    retval.reserve(data.size() * 2 + 1);
+    for (uint8_t byte : data) {
+        retval.push_back(nibble2hex[0x0F & (byte >> 4)]);
+        retval.push_back(nibble2hex[0x0F & byte]);
+    }
+    return retval;
+}
+
+struct AuthorizationSetDifferences {
+    string aName;
+    string bName;
+    AuthorizationSet aWhackB;
+    AuthorizationSet bWhackA;
+};
+
+std::ostream& operator<<(std::ostream& o, const AuthorizationSetDifferences& diffs) {
+    if (!diffs.aWhackB.empty()) {
+        o << "Set " << diffs.aName << " contains the following that " << diffs.bName << " does not"
+          << diffs.aWhackB;
+        if (!diffs.bWhackA.empty()) o << std::endl;
+    }
+
+    if (!diffs.bWhackA.empty()) {
+        o << "Set " << diffs.bName << " contains the following that " << diffs.aName << " does not"
+          << diffs.bWhackA;
+    }
+    return o;
+}
+
+// Computes and returns a \ b and b \ a ('\' is the set-difference operator, a \ b means all the
+// elements that are in a but not b, i.e. take a and whack all the elements in b) to the provided
+// stream.  The sets must be sorted.
+//
+// This provides a simple and clear view of how the two sets differ, generally much
+// easier than scrutinizing printouts of the two sets.
+AuthorizationSetDifferences difference(string aName, const AuthorizationSet& a, string bName,
+                                       const AuthorizationSet& b) {
+    AuthorizationSetDifferences diffs = {std::move(aName), std::move(bName), {}, {}};
+    std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(diffs.aWhackB));
+    std::set_difference(b.begin(), b.end(), a.begin(), a.end(), std::back_inserter(diffs.bWhackA));
+    return diffs;
+}
+
+#define DIFFERENCE(a, b) difference(#a, a, #b, b)
+
+void check_root_of_trust(const RootOfTrust& root_of_trust) {
+    char vb_meta_device_state[PROPERTY_VALUE_MAX];
+    if (property_get("ro.boot.vbmeta.device_state", vb_meta_device_state, "") == 0) return;
+
+    char vb_meta_digest[PROPERTY_VALUE_MAX];
+    EXPECT_GT(property_get("ro.boot.vbmeta.digest", vb_meta_digest, ""), 0);
+    EXPECT_EQ(vb_meta_digest, bin2hex(root_of_trust.verified_boot_hash));
+
+    // Verified boot key should be all 0's if the boot state is not verified or self signed
+    HidlBuf empty_boot_key(string(32, '\0'));
+
+    char vb_meta_bootstate[PROPERTY_VALUE_MAX];
+    auto& verified_boot_key = root_of_trust.verified_boot_key;
+    auto& verified_boot_state = root_of_trust.verified_boot_state;
+    EXPECT_GT(property_get("ro.boot.verifiedbootstate", vb_meta_bootstate, ""), 0);
+    if (!strcmp(vb_meta_bootstate, "green")) {
+        EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_VERIFIED);
+        EXPECT_NE(verified_boot_key, empty_boot_key);
+    } else if (!strcmp(vb_meta_bootstate, "yellow")) {
+        EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_SELF_SIGNED);
+        EXPECT_NE(verified_boot_key, empty_boot_key);
+    } else if (!strcmp(vb_meta_bootstate, "orange")) {
+        EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_UNVERIFIED);
+        EXPECT_EQ(verified_boot_key, empty_boot_key);
+    } else if (!strcmp(vb_meta_bootstate, "red")) {
+        EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_FAILED);
+    } else {
+        EXPECT_EQ(verified_boot_state, V4_0::KM_VERIFIED_BOOT_UNVERIFIED);
+        EXPECT_EQ(verified_boot_key, empty_boot_key);
+    }
+}
+
+void check_attestation_record(AttestationRecord attestation, const HidlBuf& challenge,
+                              AuthorizationSet expected_sw_enforced,
+                              AuthorizationSet expected_hw_enforced,
+                              SecurityLevel expected_security_level) {
+    EXPECT_EQ(41U, attestation.keymaster_version);
+    EXPECT_EQ(4U, attestation.attestation_version);
+    EXPECT_EQ(expected_security_level, attestation.attestation_security_level);
+    EXPECT_EQ(expected_security_level, attestation.keymaster_security_level);
+    EXPECT_EQ(challenge, attestation.attestation_challenge);
+
+    check_root_of_trust(attestation.root_of_trust);
+
+    // Sort all of the authorization lists, so that equality matching works.
+    expected_sw_enforced.Sort();
+    expected_hw_enforced.Sort();
+    attestation.software_enforced.Sort();
+    attestation.hardware_enforced.Sort();
+
+    EXPECT_EQ(expected_sw_enforced, attestation.software_enforced)
+            << DIFFERENCE(expected_sw_enforced, attestation.software_enforced);
+    EXPECT_EQ(expected_hw_enforced, attestation.hardware_enforced)
+            << DIFFERENCE(expected_hw_enforced, attestation.hardware_enforced);
+}
+
+}  // namespace
+
+using std::string;
+using DeviceUniqueAttestationTest = Keymaster4_1HidlTest;
+
+TEST_P(DeviceUniqueAttestationTest, StrongBoxOnly) {
+    if (SecLevel() != SecurityLevel::STRONGBOX) return;
+
+    ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder()
+                                                         .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                         .RsaSigningKey(2048, 65537)
+                                                         .Digest(Digest::SHA_2_256)
+                                                         .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+                                                         .Authorization(TAG_INCLUDE_UNIQUE_ID))));
+
+    hidl_vec<hidl_vec<uint8_t>> cert_chain;
+    EXPECT_EQ(ErrorCode::UNIMPLEMENTED,
+              convert(AttestKey(
+                      AuthorizationSetBuilder()
+                              .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+                              .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+                              .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+                      &cert_chain)));
+    CheckedDeleteKey();
+
+    ASSERT_EQ(ErrorCode::OK, convert(GenerateKey(AuthorizationSetBuilder()
+                                                         .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                         .EcdsaSigningKey(EcCurve::P_256)
+                                                         .Digest(Digest::SHA_2_256)
+                                                         .Authorization(TAG_INCLUDE_UNIQUE_ID))));
+
+    EXPECT_EQ(ErrorCode::UNIMPLEMENTED,
+              convert(AttestKey(
+                      AuthorizationSetBuilder()
+                              .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+                              .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+                      &cert_chain)));
+}
+
+TEST_P(DeviceUniqueAttestationTest, Rsa) {
+    if (SecLevel() != SecurityLevel::STRONGBOX) return;
+    ASSERT_EQ(ErrorCode::OK,
+              convert(GenerateKey(AuthorizationSetBuilder()
+                                          .Authorization(TAG_NO_AUTH_REQUIRED)
+                                          .RsaSigningKey(2048, 65537)
+                                          .Digest(Digest::SHA_2_256)
+                                          .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+                                          .Authorization(TAG_CREATION_DATETIME, 1))));
+
+    hidl_vec<hidl_vec<uint8_t>> cert_chain;
+    HidlBuf challenge("challenge");
+    HidlBuf app_id("foo");
+    EXPECT_EQ(ErrorCode::OK,
+              convert(AttestKey(AuthorizationSetBuilder()
+                                        .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+                                        .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
+                                        .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+                                &cert_chain)));
+
+    EXPECT_EQ(1U, cert_chain.size());
+    auto [err, attestation] = parse_attestation_record(cert_chain[0]);
+    EXPECT_EQ(ErrorCode::OK, err);
+
+    check_attestation_record(attestation, challenge,
+                             /* sw_enforced */
+                             AuthorizationSetBuilder()
+                                     .Authorization(TAG_CREATION_DATETIME, 1)
+                                     .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+                             /* hw_enforced */
+                             AuthorizationSetBuilder()
+                                     .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+                                     .Authorization(TAG_NO_AUTH_REQUIRED)
+                                     .RsaSigningKey(2048, 65537)
+                                     .Digest(Digest::SHA_2_256)
+                                     .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+                                     .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
+                                     .Authorization(TAG_OS_VERSION, os_version())
+                                     .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()),
+                             SecLevel());
+}
+
+TEST_P(DeviceUniqueAttestationTest, Ecdsa) {
+    if (SecLevel() != SecurityLevel::STRONGBOX) return;
+    ASSERT_EQ(ErrorCode::OK,
+              convert(GenerateKey(AuthorizationSetBuilder()
+                                          .Authorization(TAG_NO_AUTH_REQUIRED)
+                                          .EcdsaSigningKey(256)
+                                          .Digest(Digest::SHA_2_256)
+                                          .Authorization(TAG_CREATION_DATETIME, 1))));
+
+    hidl_vec<hidl_vec<uint8_t>> cert_chain;
+    HidlBuf challenge("challenge");
+    HidlBuf app_id("foo");
+    EXPECT_EQ(ErrorCode::OK,
+              convert(AttestKey(AuthorizationSetBuilder()
+                                        .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+                                        .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
+                                        .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+                                &cert_chain)));
+
+    EXPECT_EQ(1U, cert_chain.size());
+    auto [err, attestation] = parse_attestation_record(cert_chain[0]);
+    EXPECT_EQ(ErrorCode::OK, err);
+
+    check_attestation_record(attestation, challenge,
+                             /* sw_enforced */
+                             AuthorizationSetBuilder()
+                                     .Authorization(TAG_CREATION_DATETIME, 1)
+                                     .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+                             /* hw_enforced */
+                             AuthorizationSetBuilder()
+                                     .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+                                     .Authorization(TAG_NO_AUTH_REQUIRED)
+                                     .EcdsaSigningKey(256)
+                                     .Digest(Digest::SHA_2_256)
+                                     .Authorization(TAG_EC_CURVE, EcCurve::P_256)
+                                     .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
+                                     .Authorization(TAG_OS_VERSION, os_version())
+                                     .Authorization(TAG_OS_PATCHLEVEL, os_patch_level()),
+                             SecLevel());
+}
+
+INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(DeviceUniqueAttestationTest);
+
+}  // namespace test
+}  // namespace android::hardware::keymaster::V4_1
diff --git a/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp b/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp
index 4a19010..a26c688 100644
--- a/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp
+++ b/keymaster/4.1/vts/functional/EarlyBootKeyTest.cpp
@@ -14,8 +14,78 @@
  * limitations under the License.
  */
 
+#include "Keymaster4_1HidlTest.h"
+
+#include <keymasterV4_1/authorization_set.h>
+
 namespace android::hardware::keymaster::V4_1::test {
 
-// TODO(swillden): Put tests here.
+using std::string;
+
+using EarlyBootKeyTest = Keymaster4_1HidlTest;
+
+// Because VTS tests are run on fully-booted machines, we can only run negative tests for early boot
+// keys, which cannot be created or used after /data is mounted.  This is the only test we can run
+// in the normal case.  The positive test will have to be done by the Android system, when it
+// creates/uses early boot keys during boot.  It should fail to boot if the early boot key usage
+// fails.
+TEST_P(EarlyBootKeyTest, CannotCreateEarlyBootKeys) {
+    auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
+            CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::EARLY_BOOT_ENDED);
+
+    CheckedDeleteKeyData(&aesKeyData);
+    CheckedDeleteKeyData(&hmacKeyData);
+    CheckedDeleteKeyData(&rsaKeyData);
+    CheckedDeleteKeyData(&ecdsaKeyData);
+}
+
+// This is a more comprenhensive test, but it can only be run on a machine which is still in early
+// boot stage, which no proper Android device is by the time we can run VTS.  To use this,
+// un-disable it and modify vold to remove the call to earlyBootEnded().  Running the test will end
+// early boot, so you'll have to reboot between runs.
+TEST_P(EarlyBootKeyTest, DISABLED_FullTest) {
+    // Should be able to create keys, since early boot has not ended
+    auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
+            CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::OK);
+
+    // TAG_EARLY_BOOT_ONLY should be in hw-enforced.
+    EXPECT_TRUE(contains(aesKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
+    EXPECT_TRUE(contains(hmacKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
+    EXPECT_TRUE(contains(rsaKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
+    EXPECT_TRUE(contains(ecdsaKeyData.characteristics.hardwareEnforced, TAG_EARLY_BOOT_ONLY));
+
+    // Should be able to use keys, since early boot has not ended
+    EXPECT_EQ(ErrorCode::OK, UseAesKey(aesKeyData.blob));
+    EXPECT_EQ(ErrorCode::OK, UseHmacKey(hmacKeyData.blob));
+    EXPECT_EQ(ErrorCode::OK, UseRsaKey(rsaKeyData.blob));
+    EXPECT_EQ(ErrorCode::OK, UseEcdsaKey(ecdsaKeyData.blob));
+
+    // End early boot
+    Return<ErrorCode> earlyBootResult = keymaster().earlyBootEnded();
+    EXPECT_TRUE(earlyBootResult.isOk());
+    EXPECT_EQ(earlyBootResult, ErrorCode::OK);
+
+    // Should not be able to use already-created keys.
+    EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseAesKey(aesKeyData.blob));
+    EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseHmacKey(hmacKeyData.blob));
+    EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseRsaKey(rsaKeyData.blob));
+    EXPECT_EQ(ErrorCode::EARLY_BOOT_ENDED, UseEcdsaKey(ecdsaKeyData.blob));
+
+    CheckedDeleteKeyData(&aesKeyData);
+    CheckedDeleteKeyData(&hmacKeyData);
+    CheckedDeleteKeyData(&rsaKeyData);
+    CheckedDeleteKeyData(&ecdsaKeyData);
+
+    // Should not be able to create new keys
+    std::tie(aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData) =
+            CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::EARLY_BOOT_ENDED);
+
+    CheckedDeleteKeyData(&aesKeyData);
+    CheckedDeleteKeyData(&hmacKeyData);
+    CheckedDeleteKeyData(&rsaKeyData);
+    CheckedDeleteKeyData(&ecdsaKeyData);
+}
+
+INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(EarlyBootKeyTest);
 
 }  // namespace android::hardware::keymaster::V4_1::test
diff --git a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp
new file mode 100644
index 0000000..efedf28
--- /dev/null
+++ b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Keymaster4_1HidlTest.h"
+
+namespace android::hardware::keymaster::V4_1::test {
+
+using std::string;
+
+void Keymaster4_1HidlTest::SetUp() {
+    keymaster41_ = IKeymasterDevice::getService(GetParam());
+    InitializeKeymaster(keymaster41_);
+}
+
+auto Keymaster4_1HidlTest::ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation,
+                                          const string& message, const AuthorizationSet& in_params)
+        -> std::tuple<ErrorCode, string, AuthorizationSet /* out_params */> {
+    AuthorizationSet begin_out_params;
+    V4_0::ErrorCode result = Begin(operation, key_blob, in_params, &begin_out_params, &op_handle_);
+    AuthorizationSet out_params(std::move(begin_out_params));
+    if (result != V4_0::ErrorCode::OK) {
+        return {convert(result), {}, out_params};
+    }
+
+    string output;
+    size_t consumed = 0;
+    AuthorizationSet update_params;
+    AuthorizationSet update_out_params;
+    result = Update(op_handle_, update_params, message, &update_out_params, &output, &consumed);
+    out_params.push_back(update_out_params);
+    if (result != V4_0::ErrorCode::OK) {
+        return {convert(result), output, out_params};
+    }
+
+    string unused;
+    AuthorizationSet finish_params;
+    AuthorizationSet finish_out_params;
+    result = Finish(op_handle_, finish_params, message.substr(consumed), unused, &finish_out_params,
+                    &output);
+    op_handle_ = V4_0::test::kOpHandleSentinel;
+    out_params.push_back(finish_out_params);
+
+    return {convert(result), output, out_params};
+}
+
+}  // namespace android::hardware::keymaster::V4_1::test
diff --git a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
new file mode 100644
index 0000000..6332c43
--- /dev/null
+++ b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
+
+#include <KeymasterHidlTest.h>
+#include <keymasterV4_1/authorization_set.h>
+
+namespace android::hardware::keymaster::V4_1::test {
+
+using V4_0::test::HidlBuf;
+
+class Keymaster4_1HidlTest : public V4_0::test::KeymasterHidlTest {
+  public:
+    using super = V4_0::test::KeymasterHidlTest;
+
+    ErrorCode convert(V4_0::ErrorCode error_code) { return static_cast<ErrorCode>(error_code); }
+
+    // These methods hide the base class versions.
+    void SetUp();
+    IKeymasterDevice& keymaster() { return *keymaster41_; };
+
+    struct KeyData {
+        HidlBuf blob;
+        KeyCharacteristics characteristics;
+    };
+
+    std::tuple<ErrorCode, KeyData> GenerateKeyData(const AuthorizationSet& keyDescription) {
+        KeyData keyData;
+        ErrorCode errorCode = convert(
+                super::GenerateKey(keyDescription, &keyData.blob, &keyData.characteristics));
+        return {errorCode, keyData};
+    }
+
+    void CheckedDeleteKeyData(KeyData* keyData) { CheckedDeleteKey(&keyData->blob); }
+
+    template <typename TagType>
+    std::tuple<KeyData /* aesKey */, KeyData /* hmacKey */, KeyData /* rsaKey */,
+               KeyData /* ecdsaKey */>
+    CreateTestKeys(TagType tagToTest, ErrorCode expectedReturn) {
+        ErrorCode errorCode;
+
+        /* AES */
+        KeyData aesKeyData;
+        std::tie(errorCode, aesKeyData) =
+                GenerateKeyData(AuthorizationSetBuilder()
+                                        .AesEncryptionKey(128)
+                                        .Authorization(tagToTest)
+                                        .BlockMode(BlockMode::ECB)
+                                        .Padding(PaddingMode::NONE)
+                                        .Authorization(TAG_NO_AUTH_REQUIRED));
+        EXPECT_EQ(expectedReturn, errorCode);
+
+        /* HMAC */
+        KeyData hmacKeyData;
+        std::tie(errorCode, hmacKeyData) =
+                GenerateKeyData(AuthorizationSetBuilder()
+                                        .HmacKey(128)
+                                        .Authorization(tagToTest)
+                                        .Digest(Digest::SHA_2_256)
+                                        .Authorization(TAG_MIN_MAC_LENGTH, 128)
+                                        .Authorization(TAG_NO_AUTH_REQUIRED));
+        EXPECT_EQ(expectedReturn, errorCode);
+
+        /* RSA */
+        KeyData rsaKeyData;
+        std::tie(errorCode, rsaKeyData) =
+                GenerateKeyData(AuthorizationSetBuilder()
+                                        .RsaSigningKey(2048, 65537)
+                                        .Authorization(tagToTest)
+                                        .Digest(Digest::NONE)
+                                        .Padding(PaddingMode::NONE)
+                                        .Authorization(TAG_NO_AUTH_REQUIRED));
+        EXPECT_EQ(expectedReturn, errorCode);
+
+        /* ECDSA */
+        KeyData ecdsaKeyData;
+        std::tie(errorCode, ecdsaKeyData) =
+                GenerateKeyData(AuthorizationSetBuilder()
+                                        .EcdsaSigningKey(256)
+                                        .Authorization(tagToTest)
+                                        .Digest(Digest::SHA_2_256)
+                                        .Authorization(TAG_NO_AUTH_REQUIRED));
+        EXPECT_EQ(expectedReturn, errorCode);
+
+        return {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData};
+    }
+
+    std::tuple<ErrorCode, std::string /* processedMessage */, AuthorizationSet /* out_params */>
+    ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation, const std::string& message,
+                   const AuthorizationSet& in_params);
+
+    ErrorCode UseAesKey(const HidlBuf& aesKeyBlob) {
+        auto [result, ciphertext, out_params] = ProcessMessage(
+                aesKeyBlob, KeyPurpose::ENCRYPT, "1234567890123456",
+                AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE));
+        return result;
+    }
+
+    ErrorCode UseHmacKey(const HidlBuf& hmacKeyBlob) {
+        auto [result, mac, out_params] =
+                ProcessMessage(hmacKeyBlob, KeyPurpose::SIGN, "1234567890123456",
+                               AuthorizationSetBuilder().Authorization(TAG_MAC_LENGTH, 128));
+        return result;
+    }
+
+    ErrorCode UseRsaKey(const HidlBuf& rsaKeyBlob) {
+        std::string message(2048 / 8, 'a');
+        auto [result, signature, out_params] = ProcessMessage(
+                rsaKeyBlob, KeyPurpose::SIGN, message,
+                AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+        return result;
+    }
+
+    ErrorCode UseEcdsaKey(const HidlBuf& ecdsaKeyBlob) {
+        auto [result, signature, out_params] =
+                ProcessMessage(ecdsaKeyBlob, KeyPurpose::SIGN, "a",
+                               AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+        return result;
+    }
+
+    static std::vector<std::string> build_params() {
+        auto params = android::hardware::getAllHalInstanceNames(IKeymasterDevice::descriptor);
+        return params;
+    }
+
+  private:
+    sp<IKeymasterDevice> keymaster41_;
+};
+
+template <typename TypedTag>
+bool contains(hidl_vec<KeyParameter>& set, TypedTag typedTag) {
+    return std::find_if(set.begin(), set.end(), [&](const KeyParameter& param) {
+               return param.tag == static_cast<V4_0::Tag>(typedTag);
+           }) != set.end();
+}
+
+#define INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(name)                                     \
+    INSTANTIATE_TEST_SUITE_P(PerInstance, name,                                       \
+                             testing::ValuesIn(Keymaster4_1HidlTest::build_params()), \
+                             android::hardware::PrintInstanceNameToString)
+
+}  // namespace android::hardware::keymaster::V4_1::test
diff --git a/keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp b/keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp
new file mode 100644
index 0000000..671bbbf
--- /dev/null
+++ b/keymaster/4.1/vts/functional/UnlockedDeviceRequiredTest.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Keymaster4_1HidlTest.h"
+
+#include <keymasterV4_1/authorization_set.h>
+
+namespace android::hardware::keymaster::V4_1::test {
+
+using UnlockedDeviceRequiredTest = Keymaster4_1HidlTest;
+
+// This may be a problematic test.  It can't be run repeatedly without unlocking the device in
+// between runs... and on most test devices there are no enrolled credentials so it can't be
+// unlocked at all, meaning the only way to get the test to pass again on a properly-functioning
+// device is to reboot it.  For that reason, this is disabled by default.  It can be used as part of
+// a manual test process, which includes unlocking between runs, which is why it's included here.
+// Well, that and the fact that it's the only test we can do without also making calls into the
+// Gatekeeper HAL.  We haven't written any cross-HAL tests, and don't know what all of the
+// implications might be, so that may or may not be a solution.
+//
+// TODO(swillden): Use the Gatekeeper HAL to enroll some test credentials which we can verify to get
+// an unlock auth token.  If that works, enable the improved test.
+TEST_P(UnlockedDeviceRequiredTest, DISABLED_KeysBecomeUnusable) {
+    auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
+            CreateTestKeys(TAG_UNLOCKED_DEVICE_REQUIRED, ErrorCode::OK);
+
+    EXPECT_EQ(ErrorCode::OK, UseAesKey(aesKeyData.blob));
+    EXPECT_EQ(ErrorCode::OK, UseHmacKey(hmacKeyData.blob));
+    EXPECT_EQ(ErrorCode::OK, UseRsaKey(rsaKeyData.blob));
+    EXPECT_EQ(ErrorCode::OK, UseEcdsaKey(ecdsaKeyData.blob));
+
+    Return<ErrorCode> rc =
+            keymaster().deviceLocked(false /* passwordOnly */, {} /* verificationToken */);
+    ASSERT_TRUE(rc.isOk());
+    ASSERT_EQ(ErrorCode::OK, static_cast<ErrorCode>(rc));
+
+    EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseAesKey(aesKeyData.blob));
+    EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseHmacKey(hmacKeyData.blob));
+    EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseRsaKey(rsaKeyData.blob));
+    EXPECT_EQ(ErrorCode::DEVICE_LOCKED, UseEcdsaKey(ecdsaKeyData.blob));
+
+    CheckedDeleteKeyData(&aesKeyData);
+    CheckedDeleteKeyData(&hmacKeyData);
+    CheckedDeleteKeyData(&rsaKeyData);
+    CheckedDeleteKeyData(&ecdsaKeyData);
+}
+
+INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(UnlockedDeviceRequiredTest);
+
+}  // namespace android::hardware::keymaster::V4_1::test
diff --git a/neuralnetworks/1.3/IDevice.hal b/neuralnetworks/1.3/IDevice.hal
index 9afd778..8dc41f7 100644
--- a/neuralnetworks/1.3/IDevice.hal
+++ b/neuralnetworks/1.3/IDevice.hal
@@ -48,9 +48,14 @@
     /**
      * Gets the supported operations in a model.
      *
-     * getSupportedOperations indicates which operations of a model are fully
-     * supported by the vendor driver. If an operation may not be supported for
-     * any reason, getSupportedOperations must return false for that operation.
+     * getSupportedOperations indicates which operations of the top-level
+     * subgraph are fully supported by the vendor driver. If an operation may
+     * not be supported for any reason, getSupportedOperations must return
+     * false for that operation.
+     *
+     * The {@link OperationType::IF} and {@link OperationType::WHILE}
+     * operations may only be fully supported if the vendor driver fully
+     * supports all operations in the referenced subgraphs.
      *
      * @param model A model whose operations--and their corresponding operands--
      *     are to be verified by the driver.
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index 6c8fe43..a6d274a 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -17,9 +17,10 @@
 package android.hardware.neuralnetworks@1.3;
 
 import @1.0::DataLocation;
-import @1.0::OperandLifeTime;
 import @1.0::PerformanceInfo;
 import @1.0::RequestArgument;
+import @1.2::Model.ExtensionNameAndPrefix;
+import @1.2::Model.ExtensionTypeEncoding;
 import @1.2::OperandType;
 import @1.2::OperationType;
 import @1.2::SymmPerChannelQuantParams;
@@ -40,6 +41,13 @@
      */
     TENSOR_QUANT8_ASYMM_SIGNED = 14,
 
+    /**
+     * A reference to a subgraph.
+     *
+     * Must have the lifetime {@link OperandLifeTime::SUBGRAPH}.
+     */
+    SUBGRAPH = 15,
+
     /*
      * DEPRECATED. Since HAL version 1.2, extensions are the preferred
      * alternative to OEM operation and data types.
@@ -68,7 +76,7 @@
 enum OperandTypeRange : uint32_t {
     BASE_MIN        = 0,
     FUNDAMENTAL_MIN = 0,
-    FUNDAMENTAL_MAX = 14,
+    FUNDAMENTAL_MAX = 15,
     OEM_MIN         = 10000,
     OEM_MAX         = 10001,
     BASE_MAX        = 0xFFFF,
@@ -4877,6 +4885,92 @@
     QUANTIZED_LSTM = 95,
 
     /**
+     * Executes one of the two referenced subgraphs as determined by a boolean
+     * value.
+     *
+     * The inputs and outputs of the two referenced subgraphs must agree with the
+     * signature of this operation. That is, if the operation has (3 + n) inputs
+     * and m outputs, both subgraphs must have n inputs and m outputs with the same
+     * types as the corresponding operation inputs and outputs.
+     *
+     * Inputs:
+     * * 0: A value of type {@link OperandType::TENSOR_BOOL8} and shape [1]
+     *      that determines which of the two referenced subgraphs to execute.
+     * * 1: A {@link OperandType::SUBGRAPH} reference to the subgraph to be
+     *      executed if the condition is true.
+     * * 2: A {@link OperandType::SUBGRAPH} reference to the subgraph to be
+     *      executed if the condition is false.
+     * * 3 ~ (n + 2): Inputs to be passed to the subgraph selected for execution.
+     *
+     * Outputs:
+     * * 0 ~ (m - 1): Outputs produced by the selected subgraph.
+     */
+    IF = 96,
+
+    /**
+     * Executes the body subgraph until the condition subgraph outputs false.
+     *
+     * The inputs to this operation are the condition subgraph, the body subgraph,
+     * and operand values for the first iteration of the loop. The values are
+     * implicitly split into three groups of input-output, state-only, and
+     * input-only values, as described below.
+     *
+     * The outputs of this operation are the final values of input-output
+     * operands.
+     *
+     * Both the condition and body subgraph receive (m + k + n) inputs.
+     * * The first m (m >= 1) inputs are input-output operands. For the first
+     *   iteration, these are initialized from the corresponding inputs of the
+     *   WHILE operation. In subsequent iterations, their values come from the
+     *   corresponding outputs of the body subgraph produced during the previous
+     *   iteration.
+     * * The next k (k >= 0) inputs are state-only operands. They are similar to
+     *   the input-output operands, except that their values are no longer
+     *   available after the loop terminates.
+     * * The last n (n >= 0) inputs are input-only operands. Their values come
+     *   from the corresponding inputs of the WHILE operation.
+     *
+     * The body subgraph produces (m + k) outputs.
+     * * The first m outputs are input-output operands. They become the outputs
+     *   of the WHILE operation when a termination condition is reached.
+     * * The last k outputs are state-only operands. Their values are no longer
+     *   available after the loop terminates.
+     *
+     * The numbers m, k, and n are inferred by the driver as follows:
+     *     m = (WHILE operation output count)
+     *     k = (body subgraph output count) - m
+     *     n = (body subgraph input count) - m - k
+     *
+     * The pseudo-code below illustrates the flow of a WHILE operation with
+     * inputs condition, body, initial_input_output, initial_state, input_only
+     * (m = 1, k = 1, n = 1):
+     *
+     *     input_output = initial_input_output
+     *     state = initial_state
+     *     while condition(input_output, state, input_only):
+     *         input_output, state = body(input_output, state, input_only)
+     *     return input_output
+     *
+     * Inputs:
+     * * 0: A {@link OperandType::SUBGRAPH} reference to the condition
+     *      subgraph. The subgraph must have (m + k + n) inputs with
+     *      the same types as the corresponding inputs of the WHILE operation
+     *      and exactly one output of {@link OperandType::TENSOR_BOOL8}
+     *      and shape [1].
+     * * 1: A {@link OperandType::SUBGRAPH} reference to the body subgraph.
+     *      The subgraph must have (m + k + n) inputs and (m + k) outputs with
+     *      the same types as the corresponding inputs and outputs of the WHILE
+     *      operation.
+     * * (m inputs): Initial values for input-output operands.
+     * * (k inputs): Initial values for state-only operands.
+     * * (n inputs): Values for input-only operands.
+     *
+     * Outputs:
+     * * 0 ~ (m - 1): Outputs produced by the loop.
+     */
+    WHILE = 97,
+
+    /**
      * DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to
      * OEM operation and data types.
      *
@@ -4898,13 +4992,12 @@
 enum OperationTypeRange : uint32_t {
     BASE_MIN        = 0,
     FUNDAMENTAL_MIN = 0,
-    FUNDAMENTAL_MAX = 95,
+    FUNDAMENTAL_MAX = 97,
     OEM_MIN         = 10000,
     OEM_MAX         = 10000,
     BASE_MAX        = 0xFFFF,
 };
 
-
 /**
  * The capabilities of a driver.
  *
@@ -4966,6 +5059,59 @@
 };
 
 /**
+ * How an operand is used.
+ */
+enum OperandLifeTime : int32_t {
+    /**
+     * The operand is internal to the model. It's created by an operation and
+     * consumed by other operations. It must be an output operand of
+     * exactly one operation.
+     */
+    TEMPORARY_VARIABLE,
+
+    /**
+     * The operand is an input of a subgraph. It must not be an output
+     * operand of any operation.
+     *
+     * An operand can't be both input and output of a subgraph.
+     */
+    SUBGRAPH_INPUT,
+
+    /**
+     * The operand is an output of a subgraph. It must be an output
+     * operand of exactly one operation.
+     *
+     * An operand can't be both input and output of a subgraph.
+     */
+    SUBGRAPH_OUTPUT,
+
+    /**
+     * The operand is a constant found in Model.operandValues. It must
+     * not be an output operand of any operation.
+     */
+    CONSTANT_COPY,
+
+    /**
+     * The operand is a constant that was specified via a Memory
+     * object. It must not be an output operand of any operation.
+     */
+    CONSTANT_REFERENCE,
+
+    /**
+     * The operand does not have a value. This is valid only for optional
+     * arguments of operations.
+     */
+    NO_VALUE,
+
+    /**
+     * The operand is a reference to a subgraph. It must be an input to one
+     * or more {@link OperationType::IF} or {@link OperationType::WHILE}
+     * operations.
+     */
+    SUBGRAPH,
+};
+
+/**
  * Describes one operand of the model's graph.
  */
 struct Operand {
@@ -5001,7 +5147,7 @@
      *     . The operand has lifetime CONSTANT_COPY or
      *       CONSTANT_REFERENCE.
      *
-     *     . The operand has lifetime MODEL_INPUT. Fully
+     *     . The operand has lifetime SUBGRAPH_INPUT. Fully
      *       specified dimensions must either be present in the
      *       Operand or they must be provided in the corresponding
      *       RequestArgument.
@@ -5049,8 +5195,8 @@
 
     /**
      * Where to find the data for this operand.
-     * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or
-     * NO_VALUE:
+     * If the lifetime is TEMPORARY_VARIABLE, SUBGRAPH_INPUT, SUBGRAPH_OUTPUT,
+     * or NO_VALUE:
      * - All the fields must be 0.
      * If the lifetime is CONSTANT_COPY:
      * - location.poolIndex is 0.
@@ -5060,6 +5206,11 @@
      * - location.poolIndex is set.
      * - location.offset is the offset in bytes into the specified pool.
      * - location.length is set.
+     * If the lifetime is SUBGRAPH:
+     * - location.poolIndex is 0.
+     * - location.offset is the index of the referenced subgraph in
+     *   {@link Model::referenced}.
+     * - location.length is 0.
      */
     DataLocation location;
 
@@ -5098,32 +5249,19 @@
  */
 struct Model {
     /**
-     * All operands included in the model.
+     * The top-level subgraph.
      */
-    vec<Operand> operands;
+    Subgraph main;
 
     /**
-     * All operations included in the model.
+     * Referenced subgraphs.
      *
-     * The operations are sorted into execution order. Every operand
-     * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be
-     * written before it is read.
-     */
-    vec<Operation> operations;
-
-    /**
-     * Input indexes of the model. There must be at least one.
+     * Each subgraph is referenced by the main subgraph or at least one other
+     * referenced subgraph.
      *
-     * Each value corresponds to the index of the operand in "operands".
+     * There must be no reference cycles.
      */
-    vec<uint32_t> inputIndexes;
-
-    /**
-     * Output indexes of the model. There must be at least one.
-     *
-     * Each value corresponds to the index of the operand in "operands".
-     */
-    vec<uint32_t> outputIndexes;
+    vec<Subgraph> referenced;
 
     /**
      * A byte buffer containing operand data that were copied into the model.
@@ -5157,9 +5295,9 @@
      * {@link OperandTypeRange::BASE_MAX} or
      * {@link OperationTypeRange::BASE_MAX} respectively should be interpreted
      * as an extension operand. The low
-     * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value
-     * correspond to the type ID within the extension and the high
-     * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
+     * {@link @1.2::Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the
+     * value correspond to the type ID within the extension and the high
+     * {@link @1.2::Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
      * the "prefix", which maps uniquely to the extension name.
      *
      * For example, if a model contains an operation whose value is
@@ -5172,39 +5310,40 @@
      * prefix corresponding to each extension name and at most one extension
      * name corresponding to each prefix.
      */
-    vec<ExtensionNameAndPrefix> extensionNameToPrefix;
+    vec<@1.2::Model.ExtensionNameAndPrefix> extensionNameToPrefix;
+};
+
+/**
+ * An excerpt of the execution graph.
+ */
+struct Subgraph {
+    /**
+     * All operands included in the subgraph.
+     */
+    vec<Operand> operands;
 
     /**
-     * A correspondence between an extension name and a prefix of operand and
-     * operation type values.
+     * All operations included in the subgraph.
+     *
+     * The operations are sorted into execution order. Every operand
+     * with lifetime SUBGRAPH_OUTPUT or TEMPORARY_VARIABLE must be
+     * written before it is read.
      */
-    struct ExtensionNameAndPrefix {
-        /**
-         * The extension name.
-         *
-         * See {@link Extension::name} for the format specification.
-         */
-        string name;
-
-        /**
-         * The unique extension identifier within the model.
-         *
-         * See {@link Model::extensionNameToPrefix}.
-         */
-        uint16_t prefix;
-    };
+    vec<Operation> operations;
 
     /**
-     * Numeric values of extension operand and operation types have the
-     * following structure:
-     * - 16 high bits represent the "prefix", which corresponds uniquely to the
-     *   extension name.
-     * - 16 low bits represent the type ID within the extension.
+     * Input indexes of the subgraph. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
      */
-    enum ExtensionTypeEncoding : uint8_t {
-        HIGH_BITS_PREFIX = 16,
-        LOW_BITS_TYPE = 16,
-    };
+    vec<uint32_t> inputIndexes;
+
+    /**
+     * Output indexes of the subgraph. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> outputIndexes;
 };
 
 /**
diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t
index b1c72a9..f3319e5 100644
--- a/neuralnetworks/1.3/types.t
+++ b/neuralnetworks/1.3/types.t
@@ -19,9 +19,10 @@
 package android.hardware.neuralnetworks@1.3;
 
 import @1.0::DataLocation;
-import @1.0::OperandLifeTime;
 import @1.0::PerformanceInfo;
 import @1.0::RequestArgument;
+import @1.2::Model.ExtensionNameAndPrefix;
+import @1.2::Model.ExtensionTypeEncoding;
 import @1.2::OperandType;
 import @1.2::OperationType;
 import @1.2::SymmPerChannelQuantParams;
@@ -88,7 +89,6 @@
     BASE_MAX        = 0xFFFF,
 };
 
-
 /**
  * The capabilities of a driver.
  *
@@ -150,6 +150,59 @@
 };
 
 /**
+ * How an operand is used.
+ */
+enum OperandLifeTime : int32_t {
+    /**
+     * The operand is internal to the model. It's created by an operation and
+     * consumed by other operations. It must be an output operand of
+     * exactly one operation.
+     */
+    TEMPORARY_VARIABLE,
+
+    /**
+     * The operand is an input of a subgraph. It must not be an output
+     * operand of any operation.
+     *
+     * An operand can't be both input and output of a subgraph.
+     */
+    SUBGRAPH_INPUT,
+
+    /**
+     * The operand is an output of a subgraph. It must be an output
+     * operand of exactly one operation.
+     *
+     * An operand can't be both input and output of a subgraph.
+     */
+    SUBGRAPH_OUTPUT,
+
+    /**
+     * The operand is a constant found in Model.operandValues. It must
+     * not be an output operand of any operation.
+     */
+    CONSTANT_COPY,
+
+    /**
+     * The operand is a constant that was specified via a Memory
+     * object. It must not be an output operand of any operation.
+     */
+    CONSTANT_REFERENCE,
+
+    /**
+     * The operand does not have a value. This is valid only for optional
+     * arguments of operations.
+     */
+    NO_VALUE,
+
+    /**
+     * The operand is a reference to a subgraph. It must be an input to one
+     * or more {@link OperationType::IF} or {@link OperationType::WHILE}
+     * operations.
+     */
+    SUBGRAPH,
+};
+
+/**
  * Describes one operand of the model's graph.
  */
 struct Operand {
@@ -185,7 +238,7 @@
      *     . The operand has lifetime CONSTANT_COPY or
      *       CONSTANT_REFERENCE.
      *
-     *     . The operand has lifetime MODEL_INPUT. Fully
+     *     . The operand has lifetime SUBGRAPH_INPUT. Fully
      *       specified dimensions must either be present in the
      *       Operand or they must be provided in the corresponding
      *       RequestArgument.
@@ -233,8 +286,8 @@
 
     /**
      * Where to find the data for this operand.
-     * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or
-     * NO_VALUE:
+     * If the lifetime is TEMPORARY_VARIABLE, SUBGRAPH_INPUT, SUBGRAPH_OUTPUT,
+     * or NO_VALUE:
      * - All the fields must be 0.
      * If the lifetime is CONSTANT_COPY:
      * - location.poolIndex is 0.
@@ -244,6 +297,11 @@
      * - location.poolIndex is set.
      * - location.offset is the offset in bytes into the specified pool.
      * - location.length is set.
+     * If the lifetime is SUBGRAPH:
+     * - location.poolIndex is 0.
+     * - location.offset is the index of the referenced subgraph in
+     *   {@link Model::referenced}.
+     * - location.length is 0.
      */
     DataLocation location;
 
@@ -282,32 +340,19 @@
  */
 struct Model {
     /**
-     * All operands included in the model.
+     * The top-level subgraph.
      */
-    vec<Operand> operands;
+    Subgraph main;
 
     /**
-     * All operations included in the model.
+     * Referenced subgraphs.
      *
-     * The operations are sorted into execution order. Every operand
-     * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be
-     * written before it is read.
-     */
-    vec<Operation> operations;
-
-    /**
-     * Input indexes of the model. There must be at least one.
+     * Each subgraph is referenced by the main subgraph or at least one other
+     * referenced subgraph.
      *
-     * Each value corresponds to the index of the operand in "operands".
+     * There must be no reference cycles.
      */
-    vec<uint32_t> inputIndexes;
-
-    /**
-     * Output indexes of the model. There must be at least one.
-     *
-     * Each value corresponds to the index of the operand in "operands".
-     */
-    vec<uint32_t> outputIndexes;
+    vec<Subgraph> referenced;
 
     /**
      * A byte buffer containing operand data that were copied into the model.
@@ -341,9 +386,9 @@
      * {@link OperandTypeRange::BASE_MAX} or
      * {@link OperationTypeRange::BASE_MAX} respectively should be interpreted
      * as an extension operand. The low
-     * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value
-     * correspond to the type ID within the extension and the high
-     * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
+     * {@link @1.2::Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the
+     * value correspond to the type ID within the extension and the high
+     * {@link @1.2::Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
      * the "prefix", which maps uniquely to the extension name.
      *
      * For example, if a model contains an operation whose value is
@@ -356,39 +401,40 @@
      * prefix corresponding to each extension name and at most one extension
      * name corresponding to each prefix.
      */
-    vec<ExtensionNameAndPrefix> extensionNameToPrefix;
+    vec<@1.2::Model.ExtensionNameAndPrefix> extensionNameToPrefix;
+};
+
+/**
+ * An excerpt of the execution graph.
+ */
+struct Subgraph {
+    /**
+     * All operands included in the subgraph.
+     */
+    vec<Operand> operands;
 
     /**
-     * A correspondence between an extension name and a prefix of operand and
-     * operation type values.
+     * All operations included in the subgraph.
+     *
+     * The operations are sorted into execution order. Every operand
+     * with lifetime SUBGRAPH_OUTPUT or TEMPORARY_VARIABLE must be
+     * written before it is read.
      */
-    struct ExtensionNameAndPrefix {
-        /**
-         * The extension name.
-         *
-         * See {@link Extension::name} for the format specification.
-         */
-        string name;
-
-        /**
-         * The unique extension identifier within the model.
-         *
-         * See {@link Model::extensionNameToPrefix}.
-         */
-        uint16_t prefix;
-    };
+    vec<Operation> operations;
 
     /**
-     * Numeric values of extension operand and operation types have the
-     * following structure:
-     * - 16 high bits represent the "prefix", which corresponds uniquely to the
-     *   extension name.
-     * - 16 low bits represent the type ID within the extension.
+     * Input indexes of the subgraph. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
      */
-    enum ExtensionTypeEncoding : uint8_t {
-        HIGH_BITS_PREFIX = 16,
-        LOW_BITS_TYPE = 16,
-    };
+    vec<uint32_t> inputIndexes;
+
+    /**
+     * Output indexes of the subgraph. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> outputIndexes;
 };
 
 /**
diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
index fe8d907..5cb466f 100644
--- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
@@ -308,7 +308,7 @@
                 model,
                 [&fullySupportsModel, &model](ErrorStatus status, const hidl_vec<bool>& supported) {
                     ASSERT_EQ(ErrorStatus::NONE, status);
-                    ASSERT_EQ(supported.size(), model.operations.size());
+                    ASSERT_EQ(supported.size(), model.main.operations.size());
                     fullySupportsModel = std::all_of(supported.begin(), supported.end(),
                                                      [](bool valid) { return valid; });
                 });
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index 4f747f4..805d5b5 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -59,7 +59,6 @@
 using implementation::PreparedModelCallback;
 using V1_0::DataLocation;
 using V1_0::ErrorStatus;
-using V1_0::OperandLifeTime;
 using V1_0::RequestArgument;
 using V1_1::ExecutionPreference;
 using V1_2::Constant;
@@ -269,10 +268,10 @@
         }
     }
 
-    return {.operands = std::move(operands),
-            .operations = std::move(operations),
-            .inputIndexes = testModel.inputIndexes,
-            .outputIndexes = testModel.outputIndexes,
+    return {.main = {.operands = std::move(operands),
+                     .operations = std::move(operations),
+                     .inputIndexes = testModel.inputIndexes,
+                     .outputIndexes = testModel.outputIndexes},
             .operandValues = std::move(operandValues),
             .pools = std::move(pools),
             .relaxComputationFloat32toFloat16 = testModel.isRelaxed};
@@ -290,8 +289,8 @@
 }
 
 static void makeOutputDimensionsUnspecified(Model* model) {
-    for (auto i : model->outputIndexes) {
-        auto& dims = model->operands[i].dimensions;
+    for (auto i : model->main.outputIndexes) {
+        auto& dims = model->main.operands[i].dimensions;
         std::fill(dims.begin(), dims.end(), 0);
     }
 }
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
index 8395111..cc86264 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
@@ -25,7 +25,6 @@
 
 using implementation::PreparedModelCallback;
 using V1_0::ErrorStatus;
-using V1_0::OperandLifeTime;
 using V1_1::ExecutionPreference;
 using V1_2::SymmPerChannelQuantParams;
 using HidlToken =
@@ -83,22 +82,22 @@
 }
 
 static uint32_t addOperand(Model* model) {
-    return hidl_vec_push_back(&model->operands,
+    return hidl_vec_push_back(&model->main.operands,
                               {
                                       .type = OperandType::INT32,
                                       .dimensions = {},
                                       .numberOfConsumers = 0,
                                       .scale = 0.0f,
                                       .zeroPoint = 0,
-                                      .lifetime = OperandLifeTime::MODEL_INPUT,
+                                      .lifetime = OperandLifeTime::SUBGRAPH_INPUT,
                                       .location = {.poolIndex = 0, .offset = 0, .length = 0},
                               });
 }
 
 static uint32_t addOperand(Model* model, OperandLifeTime lifetime) {
     uint32_t index = addOperand(model);
-    model->operands[index].numberOfConsumers = 1;
-    model->operands[index].lifetime = lifetime;
+    model->main.operands[index].numberOfConsumers = 1;
+    model->main.operands[index].lifetime = lifetime;
     return index;
 }
 
@@ -112,13 +111,13 @@
 };
 
 static void mutateOperandTypeTest(const sp<IDevice>& device, const Model& model) {
-    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+    for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
         for (uint32_t invalidOperandType : invalidOperandTypes) {
             const std::string message = "mutateOperandTypeTest: operand " +
                                         std::to_string(operand) + " set to value " +
                                         std::to_string(invalidOperandType);
             validate(device, message, model, [operand, invalidOperandType](Model* model) {
-                model->operands[operand].type = static_cast<OperandType>(invalidOperandType);
+                model->main.operands[operand].type = static_cast<OperandType>(invalidOperandType);
             });
         }
     }
@@ -150,15 +149,15 @@
 }
 
 static void mutateOperandRankTest(const sp<IDevice>& device, const Model& model) {
-    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
-        const uint32_t invalidRank = getInvalidRank(model.operands[operand].type);
+    for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
+        const uint32_t invalidRank = getInvalidRank(model.main.operands[operand].type);
         if (invalidRank == 0) {
             continue;
         }
         const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
                                     " has rank of " + std::to_string(invalidRank);
         validate(device, message, model, [operand, invalidRank](Model* model) {
-            model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
+            model->main.operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
         });
     }
 }
@@ -190,12 +189,12 @@
 }
 
 static void mutateOperandScaleTest(const sp<IDevice>& device, const Model& model) {
-    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
-        const float invalidScale = getInvalidScale(model.operands[operand].type);
+    for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
+        const float invalidScale = getInvalidScale(model.main.operands[operand].type);
         const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
                                     " has scale of " + std::to_string(invalidScale);
         validate(device, message, model, [operand, invalidScale](Model* model) {
-            model->operands[operand].scale = invalidScale;
+            model->main.operands[operand].scale = invalidScale;
         });
     }
 }
@@ -229,15 +228,15 @@
 }
 
 static void mutateOperandZeroPointTest(const sp<IDevice>& device, const Model& model) {
-    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+    for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
         const std::vector<int32_t> invalidZeroPoints =
-                getInvalidZeroPoints(model.operands[operand].type);
+                getInvalidZeroPoints(model.main.operands[operand].type);
         for (int32_t invalidZeroPoint : invalidZeroPoints) {
             const std::string message = "mutateOperandZeroPointTest: operand " +
                                         std::to_string(operand) + " has zero point of " +
                                         std::to_string(invalidZeroPoint);
             validate(device, message, model, [operand, invalidZeroPoint](Model* model) {
-                model->operands[operand].zeroPoint = invalidZeroPoint;
+                model->main.operands[operand].zeroPoint = invalidZeroPoint;
             });
         }
     }
@@ -310,11 +309,11 @@
 
 static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, const Model& model) {
     // Do not test OEM types
-    if (type == model.operands[operand].type || type == OperandType::OEM ||
+    if (type == model.main.operands[operand].type || type == OperandType::OEM ||
         type == OperandType::TENSOR_OEM_BYTE) {
         return true;
     }
-    for (const Operation& operation : model.operations) {
+    for (const Operation& operation : model.main.operations) {
         // Skip mutateOperationOperandTypeTest for the following operations.
         // - LSH_PROJECTION's second argument is allowed to have any type.
         // - ARGMIN and ARGMAX's first argument can be any of
@@ -401,7 +400,7 @@
 }
 
 static void mutateOperationOperandTypeTest(const sp<IDevice>& device, const Model& model) {
-    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+    for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
         for (OperandType invalidOperandType : hidl_enum_range<OperandType>{}) {
             if (mutateOperationOperandTypeSkip(operand, invalidOperandType, model)) {
                 continue;
@@ -410,7 +409,7 @@
                                         std::to_string(operand) + " set to type " +
                                         toString(invalidOperandType);
             validate(device, message, model, [operand, invalidOperandType](Model* model) {
-                mutateOperand(&model->operands[operand], invalidOperandType);
+                mutateOperand(&model->main.operands[operand], invalidOperandType);
             });
         }
     }
@@ -425,13 +424,13 @@
 };
 
 static void mutateOperationTypeTest(const sp<IDevice>& device, const Model& model) {
-    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+    for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
         for (uint32_t invalidOperationType : invalidOperationTypes) {
             const std::string message = "mutateOperationTypeTest: operation " +
                                         std::to_string(operation) + " set to value " +
                                         std::to_string(invalidOperationType);
             validate(device, message, model, [operation, invalidOperationType](Model* model) {
-                model->operations[operation].type =
+                model->main.operations[operation].type =
                         static_cast<OperationType>(invalidOperationType);
             });
         }
@@ -441,14 +440,14 @@
 ///////////////////////// VALIDATE MODEL OPERATION INPUT OPERAND INDEX /////////////////////////
 
 static void mutateOperationInputOperandIndexTest(const sp<IDevice>& device, const Model& model) {
-    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
-        const uint32_t invalidOperand = model.operands.size();
-        for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
+    for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+        const uint32_t invalidOperand = model.main.operands.size();
+        for (size_t input = 0; input < model.main.operations[operation].inputs.size(); ++input) {
             const std::string message = "mutateOperationInputOperandIndexTest: operation " +
                                         std::to_string(operation) + " input " +
                                         std::to_string(input);
             validate(device, message, model, [operation, input, invalidOperand](Model* model) {
-                model->operations[operation].inputs[input] = invalidOperand;
+                model->main.operations[operation].inputs[input] = invalidOperand;
             });
         }
     }
@@ -457,14 +456,15 @@
 ///////////////////////// VALIDATE MODEL OPERATION OUTPUT OPERAND INDEX /////////////////////////
 
 static void mutateOperationOutputOperandIndexTest(const sp<IDevice>& device, const Model& model) {
-    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
-        const uint32_t invalidOperand = model.operands.size();
-        for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+    for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+        const uint32_t invalidOperand = model.main.operands.size();
+        for (size_t output = 0; output < model.main.operations[operation].outputs.size();
+             ++output) {
             const std::string message = "mutateOperationOutputOperandIndexTest: operation " +
                                         std::to_string(operation) + " output " +
                                         std::to_string(output);
             validate(device, message, model, [operation, output, invalidOperand](Model* model) {
-                model->operations[operation].outputs[output] = invalidOperand;
+                model->main.operations[operation].outputs[output] = invalidOperand;
             });
         }
     }
@@ -485,17 +485,17 @@
 }
 
 static void removeOperand(Model* model, uint32_t index) {
-    hidl_vec_removeAt(&model->operands, index);
-    for (Operation& operation : model->operations) {
+    hidl_vec_removeAt(&model->main.operands, index);
+    for (Operation& operation : model->main.operations) {
         removeValueAndDecrementGreaterValues(&operation.inputs, index);
         removeValueAndDecrementGreaterValues(&operation.outputs, index);
     }
-    removeValueAndDecrementGreaterValues(&model->inputIndexes, index);
-    removeValueAndDecrementGreaterValues(&model->outputIndexes, index);
+    removeValueAndDecrementGreaterValues(&model->main.inputIndexes, index);
+    removeValueAndDecrementGreaterValues(&model->main.outputIndexes, index);
 }
 
 static bool removeOperandSkip(size_t operand, const Model& model) {
-    for (const Operation& operation : model.operations) {
+    for (const Operation& operation : model.main.operations) {
         // Skip removeOperandTest for the following operations.
         // - SPLIT's outputs are not checked during prepareModel.
         if (operation.type == OperationType::SPLIT) {
@@ -520,7 +520,7 @@
 }
 
 static void removeOperandTest(const sp<IDevice>& device, const Model& model) {
-    for (size_t operand = 0; operand < model.operands.size(); ++operand) {
+    for (size_t operand = 0; operand < model.main.operands.size(); ++operand) {
         if (removeOperandSkip(operand, model)) {
             continue;
         }
@@ -533,14 +533,14 @@
 ///////////////////////// REMOVE OPERATION /////////////////////////
 
 static void removeOperation(Model* model, uint32_t index) {
-    for (uint32_t operand : model->operations[index].inputs) {
-        model->operands[operand].numberOfConsumers--;
+    for (uint32_t operand : model->main.operations[index].inputs) {
+        model->main.operands[operand].numberOfConsumers--;
     }
-    hidl_vec_removeAt(&model->operations, index);
+    hidl_vec_removeAt(&model->main.operations, index);
 }
 
 static void removeOperationTest(const sp<IDevice>& device, const Model& model) {
-    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+    for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
         const std::string message = "removeOperationTest: operation " + std::to_string(operation);
         validate(device, message, model,
                  [operation](Model* model) { removeOperation(model, operation); });
@@ -615,9 +615,9 @@
 }
 
 static void removeOperationInputTest(const sp<IDevice>& device, const Model& model) {
-    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
-        for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
-            const Operation& op = model.operations[operation];
+    for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+        for (size_t input = 0; input < model.main.operations[operation].inputs.size(); ++input) {
+            const Operation& op = model.main.operations[operation];
             if (removeOperationInputSkip(op, input)) {
                 continue;
             }
@@ -625,9 +625,9 @@
                                         std::to_string(operation) + ", input " +
                                         std::to_string(input);
             validate(device, message, model, [operation, input](Model* model) {
-                uint32_t operand = model->operations[operation].inputs[input];
-                model->operands[operand].numberOfConsumers--;
-                hidl_vec_removeAt(&model->operations[operation].inputs, input);
+                uint32_t operand = model->main.operations[operation].inputs[input];
+                model->main.operands[operand].numberOfConsumers--;
+                hidl_vec_removeAt(&model->main.operations[operation].inputs, input);
             });
         }
     }
@@ -636,13 +636,14 @@
 ///////////////////////// REMOVE OPERATION OUTPUT /////////////////////////
 
 static void removeOperationOutputTest(const sp<IDevice>& device, const Model& model) {
-    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
-        for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
+    for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+        for (size_t output = 0; output < model.main.operations[operation].outputs.size();
+             ++output) {
             const std::string message = "removeOperationOutputTest: operation " +
                                         std::to_string(operation) + ", output " +
                                         std::to_string(output);
             validate(device, message, model, [operation, output](Model* model) {
-                hidl_vec_removeAt(&model->operations[operation].outputs, output);
+                hidl_vec_removeAt(&model->main.operations[operation].outputs, output);
             });
         }
     }
@@ -669,15 +670,15 @@
 }
 
 static void addOperationInputTest(const sp<IDevice>& device, const Model& model) {
-    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
-        if (addOperationInputSkip(model.operations[operation])) {
+    for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
+        if (addOperationInputSkip(model.main.operations[operation])) {
             continue;
         }
         const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
         validate(device, message, model, [operation](Model* model) {
-            uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT);
-            hidl_vec_push_back(&model->operations[operation].inputs, index);
-            hidl_vec_push_back(&model->inputIndexes, index);
+            uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_INPUT);
+            hidl_vec_push_back(&model->main.operations[operation].inputs, index);
+            hidl_vec_push_back(&model->main.inputIndexes, index);
         });
     }
 }
@@ -685,13 +686,13 @@
 ///////////////////////// ADD OPERATION OUTPUT /////////////////////////
 
 static void addOperationOutputTest(const sp<IDevice>& device, const Model& model) {
-    for (size_t operation = 0; operation < model.operations.size(); ++operation) {
+    for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
         const std::string message =
                 "addOperationOutputTest: operation " + std::to_string(operation);
         validate(device, message, model, [operation](Model* model) {
-            uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
-            hidl_vec_push_back(&model->operations[operation].outputs, index);
-            hidl_vec_push_back(&model->outputIndexes, index);
+            uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_OUTPUT);
+            hidl_vec_push_back(&model->main.operations[operation].outputs, index);
+            hidl_vec_push_back(&model->main.outputIndexes, index);
         });
     }
 }
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index 3afe37d..2eaab36 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -1131,9 +1131,14 @@
 @export
 enum FrontendAnalogType : uint32_t {
     UNDEFINED = 0,
-    PAL = 1 << 0,
-    SECAM = 1 << 1,
-    NTSC = 1 << 2,
+    AUTO = 1 << 0,
+    PAL = 1 << 1,
+    PAL_M = 1 << 2,
+    PAL_N = 1 << 3,
+    PAL_60 = 1 << 4,
+    NTSC = 1 << 5,
+    NTSC_443 = 1 << 6,
+    SECAM = 1 << 7,
 };
 
 /**
@@ -1142,23 +1147,24 @@
 @export
 enum FrontendAnalogSifStandard : uint32_t {
     UNDEFINED = 0,
-    BG = 1 << 0,
-    BG_A2 = 1 << 1,
-    BG_NICAM = 1 << 2,
-    I = 1 << 3,
-    DK = 1 << 4,
-    DK1 = 1 << 5,
-    DK2 = 1 << 6,
-    DK3 = 1 << 7,
-    DK_NICAM = 1 << 8,
-    L = 1 << 9,
-    M = 1 << 10,
-    M_BTSC = 1 << 11,
-    M_A2 = 1 << 12,
-    M_EIA_J = 1 << 13,
-    I_NICAM = 1 << 14,
-    L_NICAM = 1 << 15,
-    L_PRIME = 1 << 16,
+    AUTO = 1 << 0,
+    BG = 1 << 1,
+    BG_A2 = 1 << 2,
+    BG_NICAM = 1 << 3,
+    I = 1 << 4,
+    DK = 1 << 5,
+    DK1_A2 = 1 << 6,
+    DK2_A2 = 1 << 7,
+    DK3_A2 = 1 << 8,
+    DK_NICAM = 1 << 9,
+    L = 1 << 10,
+    M = 1 << 11,
+    M_BTSC = 1 << 12,
+    M_A2 = 1 << 13,
+    M_EIAJ = 1 << 14,
+    I_NICAM = 1 << 15,
+    L_NICAM = 1 << 16,
+    L_PRIME = 1 << 17,
 };
 
 /**