Merge "Updating CDDL schemas to match the finalized spec."
diff --git a/audio/7.0/config/update_audio_policy_config.sh b/audio/7.0/config/update_audio_policy_config.sh
index 159fa35..c475dd1 100755
--- a/audio/7.0/config/update_audio_policy_config.sh
+++ b/audio/7.0/config/update_audio_policy_config.sh
@@ -41,7 +41,7 @@
 
 set -euo pipefail
 
-if (echo "$@" | grep -qe -h); then
+if (echo "$@" | grep -qe "^-h"); then
     echo "This script will update Audio Policy Manager config file"
     echo "to the format required by V7.0 XSD schema from a previous"
     echo "version."
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index bbc14ad..898c22d 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "audiohalservice"
 
+#include <signal.h>
 #include <string>
 #include <vector>
 
@@ -45,6 +46,8 @@
 }
 
 int main(int /* argc */, char* /* argv */ []) {
+    signal(SIGPIPE, SIG_IGN);
+
     ::android::ProcessState::initWithDriver("/dev/vndbinder");
     // start a threadpool for vndbinder interactions
     ::android::ProcessState::self()->startThreadPool();
diff --git a/bluetooth/audio/2.1/default/Android.bp b/bluetooth/audio/2.1/default/Android.bp
index 5c30f79..3000223 100644
--- a/bluetooth/audio/2.1/default/Android.bp
+++ b/bluetooth/audio/2.1/default/Android.bp
@@ -19,6 +19,7 @@
         "A2dpSoftwareAudioProvider.cpp",
         "HearingAidAudioProvider.cpp",
         "LeAudioAudioProvider.cpp",
+        "LeAudioOffloadAudioProvider.cpp",
     ],
     header_libs: ["libhardware_headers"],
     shared_libs: [
diff --git a/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.cpp b/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.cpp
index e1b1ac6..b0d171a 100644
--- a/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.cpp
+++ b/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.cpp
@@ -41,8 +41,12 @@
     BluetoothAudioProvidersFactory::hearing_aid_provider_instance_;
 LeAudioOutputAudioProvider
     BluetoothAudioProvidersFactory::leaudio_output_provider_instance_;
+LeAudioOffloadOutputAudioProvider
+    BluetoothAudioProvidersFactory::leaudio_offload_output_provider_instance_;
 LeAudioInputAudioProvider
     BluetoothAudioProvidersFactory::leaudio_input_provider_instance_;
+LeAudioOffloadInputAudioProvider
+    BluetoothAudioProvidersFactory::leaudio_offload_input_provider_instance_;
 
 Return<void> BluetoothAudioProvidersFactory::openProvider(
     const V2_0::SessionType sessionType, openProvider_cb _hidl_cb) {
@@ -90,9 +94,15 @@
     case SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH:
       provider = &leaudio_output_provider_instance_;
       break;
+    case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH:
+      provider = &leaudio_offload_output_provider_instance_;
+      break;
     case SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH:
       provider = &leaudio_input_provider_instance_;
       break;
+    case SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH:
+      provider = &leaudio_offload_input_provider_instance_;
+      break;
     default:
       status = BluetoothAudioStatus::FAILURE;
   }
diff --git a/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.h b/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.h
index fd83694..f8f557e 100644
--- a/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.h
+++ b/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.h
@@ -23,6 +23,7 @@
 #include "BluetoothAudioProvider.h"
 #include "HearingAidAudioProvider.h"
 #include "LeAudioAudioProvider.h"
+#include "LeAudioOffloadAudioProvider.h"
 
 namespace android {
 namespace hardware {
@@ -55,6 +56,8 @@
   static HearingAidAudioProvider hearing_aid_provider_instance_;
   static LeAudioOutputAudioProvider leaudio_output_provider_instance_;
   static LeAudioInputAudioProvider leaudio_input_provider_instance_;
+  static LeAudioOffloadOutputAudioProvider leaudio_offload_output_provider_instance_;
+  static LeAudioOffloadInputAudioProvider leaudio_offload_input_provider_instance_;
 };
 
 extern "C" IBluetoothAudioProvidersFactory*
diff --git a/bluetooth/audio/2.1/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/2.1/default/LeAudioOffloadAudioProvider.cpp
new file mode 100644
index 0000000..c11bdad
--- /dev/null
+++ b/bluetooth/audio/2.1/default/LeAudioOffloadAudioProvider.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BTAudioProviderLeAudioOffload"
+
+#include "LeAudioOffloadAudioProvider.h"
+
+#include <android-base/logging.h>
+
+#include "BluetoothAudioSessionReport_2_1.h"
+#include "BluetoothAudioSupportedCodecsDB_2_1.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::bluetooth::audio::BluetoothAudioSessionReport_2_1;
+using ::android::hardware::Void;
+using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using ::android::hardware::bluetooth::audio::V2_1::SampleRate;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+LeAudioOffloadOutputAudioProvider::LeAudioOffloadOutputAudioProvider()
+    : LeAudioOffloadAudioProvider() {
+  session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH;
+}
+
+LeAudioOffloadInputAudioProvider::LeAudioOffloadInputAudioProvider()
+    : LeAudioOffloadAudioProvider() {
+  session_type_ = SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH;
+}
+
+LeAudioOffloadAudioProvider::LeAudioOffloadAudioProvider()
+    : BluetoothAudioProvider() {}
+
+bool LeAudioOffloadAudioProvider::isValid(const V2_0::SessionType& sessionType) {
+  LOG(ERROR) << __func__ << ", invalid session type for Offloaded Le Audio provider: "
+             << toString(sessionType);
+
+  return false;
+}
+
+bool LeAudioOffloadAudioProvider::isValid(const SessionType& sessionType) {
+  return (sessionType == session_type_);
+}
+
+Return<void> LeAudioOffloadAudioProvider::startSession_2_1(
+    const sp<V2_0::IBluetoothAudioPort>& hostIf,
+    const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+  /**
+   * Initialize the audio platform if audioConfiguration is supported.
+   * Save the IBluetoothAudioPort interface, so that it can be used
+   * later to send stream control commands to the HAL client, based on
+   * interaction with Audio framework.
+   */
+  if (audioConfig.getDiscriminator() !=
+      AudioConfiguration::hidl_discriminator::leAudioCodecConfig) {
+    LOG(WARNING) << __func__
+                 << " - Invalid Audio Configuration=" << toString(audioConfig);
+    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+             DataMQ::Descriptor());
+    return Void();
+  }
+
+  if (!android::bluetooth::audio::IsOffloadLeAudioConfigurationValid(session_type_,
+                 audioConfig.leAudioCodecConfig())) {
+    LOG(WARNING) << __func__ << " - Unsupported LC3 Offloaded Configuration="
+                 << toString(audioConfig.leAudioCodecConfig());
+    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+             DataMQ::Descriptor());
+    return Void();
+  }
+
+  return BluetoothAudioProvider::startSession_2_1(hostIf, audioConfig,
+                                                  _hidl_cb);
+}
+
+Return<void> LeAudioOffloadAudioProvider::onSessionReady(startSession_cb _hidl_cb) {
+  BluetoothAudioSessionReport_2_1::OnSessionStarted(session_type_, stack_iface_,
+                                                    nullptr, audio_config_);
+  _hidl_cb(BluetoothAudioStatus::SUCCESS, DataMQ::Descriptor());
+  return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/2.1/default/LeAudioOffloadAudioProvider.h
new file mode 100644
index 0000000..564e9a3
--- /dev/null
+++ b/bluetooth/audio/2.1/default/LeAudioOffloadAudioProvider.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/bluetooth/audio/2.1/types.h>
+
+#include "BluetoothAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_1 {
+namespace implementation {
+
+class LeAudioOffloadAudioProvider : public BluetoothAudioProvider {
+ public:
+  LeAudioOffloadAudioProvider();
+
+  bool isValid(const SessionType& sessionType) override;
+  bool isValid(const V2_0::SessionType& sessionType) override;
+
+  Return<void> startSession_2_1(const sp<V2_0::IBluetoothAudioPort>& hostIf,
+                                const AudioConfiguration& audioConfig,
+                                startSession_cb _hidl_cb) override;
+
+ private:
+  Return<void> onSessionReady(startSession_cb _hidl_cb) override;
+};
+
+class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
+ public:
+  LeAudioOffloadOutputAudioProvider();
+};
+
+class LeAudioOffloadInputAudioProvider : public LeAudioOffloadAudioProvider {
+ public:
+  LeAudioOffloadInputAudioProvider();
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_1.h b/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_1.h
index 4d7be21..95f7408 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_1.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSessionControl_2_1.h
@@ -35,7 +35,7 @@
     std::shared_ptr<BluetoothAudioSession_2_1> session_ptr =
         BluetoothAudioSessionInstance_2_1::GetSessionInstance(session_type);
     if (session_ptr != nullptr) {
-      return session_ptr->GetAudioSession()->IsSessionReady();
+      return session_ptr->IsSessionReady();
     }
     return false;
   }
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp
index 9d91196..c250ef1 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.cpp
@@ -60,6 +60,16 @@
   }
 }
 
+bool BluetoothAudioSession_2_1::IsSessionReady() {
+  if (session_type_2_1_ !=
+      SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+    return audio_session->IsSessionReady();
+  }
+
+  std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
+  return audio_session->stack_iface_ != nullptr;
+}
+
 std::shared_ptr<BluetoothAudioSession>
 BluetoothAudioSession_2_1::GetAudioSession() {
   return audio_session;
@@ -70,7 +80,7 @@
 const ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration
 BluetoothAudioSession_2_1::GetAudioConfig() {
   std::lock_guard<std::recursive_mutex> guard(audio_session->mutex_);
-  if (audio_session->IsSessionReady()) {
+  if (IsSessionReady()) {
     // If session is unknown it means it should be 2.0 type
     if (session_type_2_1_ != SessionType_2_1::UNKNOWN)
       return audio_config_2_1_;
@@ -110,20 +120,29 @@
            SessionType_2_1::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH ||
        session_type_2_1_ ==
            SessionType_2_1::LE_AUDIO_SOFTWARE_DECODED_DATAPATH);
-  bool is_offload_session =
+  bool is_offload_a2dp_session =
       (session_type_2_1_ == SessionType_2_1::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+  bool is_offload_le_audio_session =
+      (session_type_2_1_ == SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+       session_type_2_1_ == SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH);
   auto audio_config_discriminator = audio_config.getDiscriminator();
   bool is_software_audio_config =
       (is_software_session &&
        audio_config_discriminator ==
            ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration::
                hidl_discriminator::pcmConfig);
-  bool is_offload_audio_config =
-      (is_offload_session &&
+  bool is_a2dp_offload_audio_config =
+      (is_offload_a2dp_session &&
        audio_config_discriminator ==
            ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration::
                hidl_discriminator::codecConfig);
-  if (!is_software_audio_config && !is_offload_audio_config) {
+  bool is_le_audio_offload_audio_config =
+      (is_offload_le_audio_session &&
+       audio_config_discriminator ==
+           ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration::
+               hidl_discriminator::leAudioCodecConfig);
+  if (!is_software_audio_config && !is_a2dp_offload_audio_config &&
+      !is_le_audio_offload_audio_config) {
     return false;
   }
   audio_config_2_1_ = audio_config;
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h
index 5a35153..db82c73 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSession_2_1.h
@@ -50,6 +50,10 @@
       const ::android::hardware::bluetooth::audio::V2_1::SessionType&
           session_type);
 
+  // The function helps to check if this session is ready or not
+  // @return: true if the Bluetooth stack has started the specified session
+  bool IsSessionReady();
+
   std::shared_ptr<BluetoothAudioSession> GetAudioSession();
 
   // The report function is used to report that the Bluetooth stack has started
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_1.cpp b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_1.cpp
index 8b0b0f7..c90ce6d 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_1.cpp
+++ b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_1.cpp
@@ -122,6 +122,21 @@
   return false;
 }
 
+bool IsOffloadLeAudioConfigurationValid(
+    const ::android::hardware::bluetooth::audio::V2_1::SessionType&
+        session_type,
+    const ::android::hardware::bluetooth::audio::V2_1::Lc3CodecConfiguration&) {
+
+  if (session_type != SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+      session_type != SessionType_2_1::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+    return false;
+  }
+
+  //TODO: perform checks on le_audio_codec_config once we know supported parameters
+
+  return true;
+}
+
 }  // namespace audio
 }  // namespace bluetooth
 }  // namespace android
diff --git a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_1.h b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_1.h
index 746d9c0..a52636c 100644
--- a/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_1.h
+++ b/bluetooth/audio/utils/session/BluetoothAudioSupportedCodecsDB_2_1.h
@@ -41,6 +41,11 @@
     const ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration&
         codec_config);
 
+bool IsOffloadLeAudioConfigurationValid(
+    const ::android::hardware::bluetooth::audio::V2_1::SessionType&
+        session_type,
+    const ::android::hardware::bluetooth::audio::V2_1::Lc3CodecConfiguration&
+        le_audio_codec_config);
 }  // namespace audio
 }  // namespace bluetooth
 }  // namespace android
diff --git a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
index 362ab41..615fde0 100644
--- a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
+++ b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
@@ -496,10 +496,26 @@
  *  - program changes exactly to what was requested.
  */
 TEST_P(BroadcastRadioHalTest, DabTune) {
+    Result halResult;
+    hidl_vec<DabTableEntry> config;
+    auto cb = [&](Result result, hidl_vec<DabTableEntry> configCb) {
+        halResult = result;
+        config = configCb;
+    };
+    auto hidlResult = mModule->getDabRegionConfig(cb);
+    ASSERT_TRUE(hidlResult.isOk());
+
+    if (halResult == Result::NOT_SUPPORTED) {
+        printSkipped("DAB not supported");
+        return;
+    }
+    ASSERT_EQ(Result::OK, halResult);
+    ASSERT_NE(config.size(), 0U);
+
     ASSERT_TRUE(openSession());
 
     ProgramSelector sel = {};
-    uint64_t freq = 178352;
+    uint64_t freq = config[config.size() / 2].frequency;
     sel.primaryId = make_identifier(IdentifierType::DAB_FREQUENCY,freq);
 
     std::this_thread::sleep_for(gTuneWorkaround);
diff --git a/current.txt b/current.txt
index cd1446d..88b067d 100644
--- a/current.txt
+++ b/current.txt
@@ -836,4 +836,7 @@
 ead4ec8713a2cb40906fe31ba793d21a6b1190143c446690d16a6ea686aa2fea android.hardware.tetheroffload.control@1.1::ITetheringOffloadCallback
 e34b4c7bec5e032c14804707ca924dd6b99ed5ba139da7505fe7d698d0fe178f android.hardware.tetheroffload.control@1.1::types
 
+# ABI preserving changes to HALs during Android T
+62ace52d9c3ff1f60f94118557a2aaf0b953513e59dcd34d5f94ae28d4c7e780 android.hardware.fastboot@1.0::IFastboot
+
 # There should be no more HIDL HALs - please use AIDL instead.
diff --git a/fastboot/1.0/IFastboot.hal b/fastboot/1.0/IFastboot.hal
index dce3ad7..b39061c 100644
--- a/fastboot/1.0/IFastboot.hal
+++ b/fastboot/1.0/IFastboot.hal
@@ -33,7 +33,7 @@
     /**
      * Executes a fastboot OEM command.
      *
-     * @param oemCmdArgs The oem command that is passed to the fastboot HAL.
+     * @param oemCmd The oem command that is passed to the fastboot HAL.
      * @return result Returns the status SUCCESS if the operation is successful,
      *     INVALID_ARGUMENT for bad arguments,
      *     FAILURE_UNKNOWN for an invalid/unsupported command.
diff --git a/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp b/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
index 7d32ced..618624e 100644
--- a/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
+++ b/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
@@ -236,6 +236,10 @@
   generatePassword(password, 0);
   enrollNewPassword(password, enrollRsp, true);
   verifyPassword(password, enrollRsp.data, 1, verifyRsp, true);
+
+  ALOGI("Testing unenrolled password doesn't verify");
+  generatePassword(password, 1);
+  verifyPassword(password, enrollRsp.data, 1, verifyRsp, false);
   ALOGI("Testing Enroll+Verify done");
 }
 
diff --git a/identity/aidl/default/common/WritableIdentityCredential.cpp b/identity/aidl/default/common/WritableIdentityCredential.cpp
index 25f129b..200ee61 100644
--- a/identity/aidl/default/common/WritableIdentityCredential.cpp
+++ b/identity/aidl/default/common/WritableIdentityCredential.cpp
@@ -210,6 +210,15 @@
                 "numAccessControlProfileRemaining_ is not zero"));
     }
 
+    // Ensure passed-in profile ids reference valid access control profiles
+    for (const int32_t id : accessControlProfileIds) {
+        if (accessControlProfileIds_.find(id) == accessControlProfileIds_.end()) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_DATA,
+                    "An id in accessControlProfileIds references non-existing ACP"));
+        }
+    }
+
     if (remainingEntryCounts_.size() == 0) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                 IIdentityCredentialStore::STATUS_INVALID_DATA, "No more namespaces to add to"));
diff --git a/identity/aidl/vts/DeleteCredentialTests.cpp b/identity/aidl/vts/DeleteCredentialTests.cpp
index d3addf4..7627c9c 100644
--- a/identity/aidl/vts/DeleteCredentialTests.cpp
+++ b/identity/aidl/vts/DeleteCredentialTests.cpp
@@ -102,7 +102,7 @@
     ASSERT_TRUE(wc->addAccessControlProfile(1, {}, false, 0, 0, &sacp).isOk());
 
     // Single entry - don't care about the returned encrypted data
-    ASSERT_TRUE(wc->beginAddEntry({0}, "ns", "Some Data", 1).isOk());
+    ASSERT_TRUE(wc->beginAddEntry({1}, "ns", "Some Data", 1).isOk());
     vector<uint8_t> encryptedData;
     ASSERT_TRUE(wc->addEntryValue({9}, &encryptedData).isOk());
 
diff --git a/identity/aidl/vts/ProveOwnershipTests.cpp b/identity/aidl/vts/ProveOwnershipTests.cpp
index fa0e293..c622193 100644
--- a/identity/aidl/vts/ProveOwnershipTests.cpp
+++ b/identity/aidl/vts/ProveOwnershipTests.cpp
@@ -102,7 +102,7 @@
     ASSERT_TRUE(wc->addAccessControlProfile(1, {}, false, 0, 0, &sacp).isOk());
 
     // Single entry - don't care about the returned encrypted data
-    ASSERT_TRUE(wc->beginAddEntry({0}, "ns", "Some Data", 1).isOk());
+    ASSERT_TRUE(wc->beginAddEntry({1}, "ns", "Some Data", 1).isOk());
     vector<uint8_t> encryptedData;
     ASSERT_TRUE(wc->addEntryValue({9}, &encryptedData).isOk());
 
diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp
index 4547624..7f4674d 100644
--- a/identity/support/src/IdentityCredentialSupport.cpp
+++ b/identity/support/src/IdentityCredentialSupport.cpp
@@ -644,7 +644,7 @@
     // the VTS tests. Of course, this is a pretend-only game since hopefully no
     // relying party is ever going to trust our batch key and those keys above
     // it.
-    ::keymaster::PureSoftKeymasterContext context(::keymaster::KmVersion::KEYMASTER_4_1,
+    ::keymaster::PureSoftKeymasterContext context(::keymaster::KmVersion::KEYMINT_1,
                                                   KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT);
 
     keymaster_error_t error;
@@ -682,10 +682,9 @@
 
     i2d_X509_NAME(subjectName.get(), &subjectPtr);
 
-    uint64_t nowMilliSeconds = time(nullptr) * 1000;
     ::keymaster::AuthorizationSet auth_set(
             ::keymaster::AuthorizationSetBuilder()
-                    .Authorization(::keymaster::TAG_CERTIFICATE_NOT_BEFORE, nowMilliSeconds)
+                    .Authorization(::keymaster::TAG_CERTIFICATE_NOT_BEFORE, activeTimeMilliSeconds)
                     .Authorization(::keymaster::TAG_CERTIFICATE_NOT_AFTER, expireTimeMilliSeconds)
                     .Authorization(::keymaster::TAG_ATTESTATION_CHALLENGE, challenge.data(),
                                    challenge.size())
diff --git a/keymaster/4.0/support/attestation_record.cpp b/keymaster/4.0/support/attestation_record.cpp
index bc294bd..342b3e2 100644
--- a/keymaster/4.0/support/attestation_record.cpp
+++ b/keymaster/4.0/support/attestation_record.cpp
@@ -71,6 +71,7 @@
     ASN1_INTEGER_SET* padding;
     ASN1_INTEGER* ec_curve;
     ASN1_INTEGER* rsa_public_exponent;
+    ASN1_NULL* rollback_resistance;
     ASN1_INTEGER* active_date_time;
     ASN1_INTEGER* origination_expire_date_time;
     ASN1_INTEGER* usage_expire_date_time;
@@ -78,56 +79,84 @@
     ASN1_INTEGER* user_auth_type;
     ASN1_INTEGER* auth_timeout;
     ASN1_NULL* allow_while_on_body;
+    ASN1_NULL* trusted_user_presence_required;
+    ASN1_NULL* trusted_confirmation_required;
+    ASN1_NULL* unlocked_device_required;
     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_OCTET_STRING* attestation_id_brand;
+    ASN1_OCTET_STRING* attestation_id_device;
+    ASN1_OCTET_STRING* attestation_id_product;
+    ASN1_OCTET_STRING* attestation_id_serial;
+    ASN1_OCTET_STRING* attestation_id_imei;
+    ASN1_OCTET_STRING* attestation_id_meid;
+    ASN1_OCTET_STRING* attestation_id_manufacturer;
+    ASN1_OCTET_STRING* attestation_id_model;
     ASN1_INTEGER* vendor_patchlevel;
     ASN1_INTEGER* boot_patchlevel;
 } 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_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, attestation_application_id, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_brand, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_BRAND.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_device, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_DEVICE.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_product, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_PRODUCT.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_serial, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_SERIAL.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_imei, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_IMEI.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_meid, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_MEID.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_manufacturer, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_MANUFACTURER.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_model, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_MODEL.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_SEQUENCE_END(KM_AUTH_LIST);
 IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
 
@@ -259,6 +288,14 @@
     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->attestation_id_brand, TAG_ATTESTATION_ID_BRAND, auth_list);
+    copyAuthTag(record->attestation_id_device, TAG_ATTESTATION_ID_DEVICE, auth_list);
+    copyAuthTag(record->attestation_id_product, TAG_ATTESTATION_ID_PRODUCT, auth_list);
+    copyAuthTag(record->attestation_id_serial, TAG_ATTESTATION_ID_SERIAL, auth_list);
+    copyAuthTag(record->attestation_id_imei, TAG_ATTESTATION_ID_IMEI, auth_list);
+    copyAuthTag(record->attestation_id_meid, TAG_ATTESTATION_ID_MEID, auth_list);
+    copyAuthTag(record->attestation_id_manufacturer, TAG_ATTESTATION_ID_MANUFACTURER, auth_list);
+    copyAuthTag(record->attestation_id_model, TAG_ATTESTATION_ID_MODEL, 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,
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 9e37ed0..01c502c 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -96,6 +96,18 @@
     return count > 0;
 }
 
+// If the given property is available, add it to the tag set under the given tag ID.
+template <Tag tag>
+void add_tag_from_prop(AuthorizationSetBuilder* tags, TypedTag<TagType::BYTES, tag> ttag,
+                       const char* prop) {
+    char value[PROPERTY_VALUE_MAX];
+    int len = property_get(prop, value, /* default = */ "");
+    if (len > 0) {
+        tags->Authorization(ttag, reinterpret_cast<const uint8_t*>(value),
+                            static_cast<size_t>(len));
+    }
+}
+
 constexpr char hex_value[256] = {0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
                                  0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
                                  0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
@@ -4409,6 +4421,95 @@
 }
 
 /*
+ * AttestationTest.EcAttestationID
+ *
+ * Verifies that attesting to EC keys with correct attestation ID fields works and generates the
+ * expected output.
+ */
+TEST_P(AttestationTest, EcAttestationID) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .EcdsaSigningKey(EcCurve::P_256)
+                                                 .Digest(Digest::SHA_2_256)
+                                                 .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+    // Collection of valid attestation ID tags.
+    auto attestation_id_tags = AuthorizationSetBuilder();
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
+                      "ro.product.manufacturer");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
+
+    for (const KeyParameter& tag : attestation_id_tags) {
+        AuthorizationSetBuilder builder =
+                AuthorizationSetBuilder()
+                        .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+                        .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo"));
+        // Include one of the (valid) attestation ID tags.
+        builder.push_back(tag);
+        hidl_vec<hidl_vec<uint8_t>> cert_chain;
+        auto result = AttestKey(builder, &cert_chain);
+        if (result == ErrorCode::CANNOT_ATTEST_IDS) {
+            continue;
+        }
+
+        ASSERT_EQ(ErrorCode::OK, result);
+        EXPECT_GE(cert_chain.size(), 2U);
+
+        std::vector<KeyParameter> expected_hw_enforced = key_characteristics_.hardwareEnforced;
+        expected_hw_enforced.push_back(tag);
+
+        EXPECT_TRUE(verify_attestation_record(
+                "challenge", "foo", key_characteristics_.softwareEnforced,
+                hidl_vec<KeyParameter>(expected_hw_enforced), SecLevel(), cert_chain[0]));
+    }
+}
+
+/*
+ * AttestationTest.EcAttestationMismatchID
+ *
+ * Verifies that attesting to EC keys with incorrect attestation ID fields fails.
+ */
+TEST_P(AttestationTest, EcAttestationMismatchID) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .EcdsaSigningKey(EcCurve::P_256)
+                                                 .Digest(Digest::SHA_2_256)
+                                                 .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+    // Collection of invalid attestation ID tags.
+    std::string invalid = "completely-invalid";
+    auto invalid_tags =
+            AuthorizationSetBuilder()
+                    .Authorization(V4_0::TAG_ATTESTATION_ID_BRAND, invalid.data(), invalid.size())
+                    .Authorization(V4_0::TAG_ATTESTATION_ID_DEVICE, invalid.data(), invalid.size())
+                    .Authorization(V4_0::TAG_ATTESTATION_ID_PRODUCT, invalid.data(), invalid.size())
+                    .Authorization(V4_0::TAG_ATTESTATION_ID_SERIAL, invalid.data(), invalid.size())
+                    .Authorization(V4_0::TAG_ATTESTATION_ID_IMEI, invalid.data(), invalid.size())
+                    .Authorization(V4_0::TAG_ATTESTATION_ID_MEID, invalid.data(), invalid.size())
+                    .Authorization(V4_0::TAG_ATTESTATION_ID_MANUFACTURER, invalid.data(),
+                                   invalid.size())
+                    .Authorization(V4_0::TAG_ATTESTATION_ID_MODEL, invalid.data(), invalid.size());
+
+    for (const KeyParameter& invalid_tag : invalid_tags) {
+        AuthorizationSetBuilder builder =
+                AuthorizationSetBuilder()
+                        .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+                        .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo"));
+        // Include one of the invalid attestation ID tags.
+        builder.push_back(invalid_tag);
+        hidl_vec<hidl_vec<uint8_t>> cert_chain;
+        auto result = AttestKey(builder, &cert_chain);
+
+        EXPECT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG)
+                << "result: " << static_cast<int32_t>(result);
+    }
+}
+
+/*
  * AttestationTest.EcAttestationRequiresAttestationAppId
  *
  * Verifies that attesting to EC keys requires app ID
diff --git a/keymaster/4.1/support/attestation_record.cpp b/keymaster/4.1/support/attestation_record.cpp
index 207a7e8..15230d5 100644
--- a/keymaster/4.1/support/attestation_record.cpp
+++ b/keymaster/4.1/support/attestation_record.cpp
@@ -79,6 +79,8 @@
     ASN1_INTEGER_SET* padding;
     ASN1_INTEGER* ec_curve;
     ASN1_INTEGER* rsa_public_exponent;
+    ASN1_NULL* rollback_resistance;
+    ASN1_NULL* early_boot_only;
     ASN1_INTEGER* active_date_time;
     ASN1_INTEGER* origination_expire_date_time;
     ASN1_INTEGER* usage_expire_date_time;
@@ -86,21 +88,27 @@
     ASN1_INTEGER* user_auth_type;
     ASN1_INTEGER* auth_timeout;
     ASN1_NULL* allow_while_on_body;
+    ASN1_NULL* trusted_user_presence_required;
+    ASN1_NULL* trusted_confirmation_required;
+    ASN1_NULL* unlocked_device_required;
     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_OCTET_STRING* attestation_id_brand;
+    ASN1_OCTET_STRING* attestation_id_device;
+    ASN1_OCTET_STRING* attestation_id_product;
+    ASN1_OCTET_STRING* attestation_id_serial;
+    ASN1_OCTET_STRING* attestation_id_imei;
+    ASN1_OCTET_STRING* attestation_id_meid;
+    ASN1_OCTET_STRING* attestation_id_manufacturer;
+    ASN1_OCTET_STRING* attestation_id_model;
     ASN1_INTEGER* vendor_patchlevel;
     ASN1_INTEGER* boot_patchlevel;
-    ASN1_NULL* early_boot_only;
     ASN1_NULL* device_unique_attestation;
     ASN1_NULL* identity_credential_key;
 } KM_AUTH_LIST;
@@ -116,6 +124,7 @@
                      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, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.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()),
@@ -138,12 +147,27 @@
         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, attestation_application_id, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_brand, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_BRAND.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_device, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_DEVICE.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_product, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_PRODUCT.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_serial, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_SERIAL.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_imei, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_IMEI.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_meid, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_MEID.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_manufacturer, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_MANUFACTURER.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_model, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_MODEL.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_EXP_OPT(KM_AUTH_LIST, identity_credential_key, ASN1_NULL,
@@ -279,6 +303,14 @@
     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->attestation_id_brand, TAG_ATTESTATION_ID_BRAND, auth_list);
+    copyAuthTag(record->attestation_id_device, TAG_ATTESTATION_ID_DEVICE, auth_list);
+    copyAuthTag(record->attestation_id_product, TAG_ATTESTATION_ID_PRODUCT, auth_list);
+    copyAuthTag(record->attestation_id_serial, TAG_ATTESTATION_ID_SERIAL, auth_list);
+    copyAuthTag(record->attestation_id_imei, TAG_ATTESTATION_ID_IMEI, auth_list);
+    copyAuthTag(record->attestation_id_meid, TAG_ATTESTATION_ID_MEID, auth_list);
+    copyAuthTag(record->attestation_id_manufacturer, TAG_ATTESTATION_ID_MANUFACTURER, auth_list);
+    copyAuthTag(record->attestation_id_model, TAG_ATTESTATION_ID_MODEL, 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,
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 40eb142..e8db56a 100644
--- a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
@@ -53,6 +53,14 @@
 using V4_0::TAG_ASSOCIATED_DATA;
 using V4_0::TAG_ATTESTATION_APPLICATION_ID;
 using V4_0::TAG_ATTESTATION_CHALLENGE;
+using V4_0::TAG_ATTESTATION_ID_BRAND;
+using V4_0::TAG_ATTESTATION_ID_DEVICE;
+using V4_0::TAG_ATTESTATION_ID_IMEI;
+using V4_0::TAG_ATTESTATION_ID_MANUFACTURER;
+using V4_0::TAG_ATTESTATION_ID_MEID;
+using V4_0::TAG_ATTESTATION_ID_MODEL;
+using V4_0::TAG_ATTESTATION_ID_PRODUCT;
+using V4_0::TAG_ATTESTATION_ID_SERIAL;
 using V4_0::TAG_AUTH_TIMEOUT;
 using V4_0::TAG_BLOB_USAGE_REQUIREMENTS;
 using V4_0::TAG_BLOCK_MODE;
diff --git a/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
index 0639da8..4a57f44 100644
--- a/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
+++ b/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "keymaster_hidl_hal_test"
 #include <cutils/log.h>
+#include <vector>
 
 #include "Keymaster4_1HidlTest.h"
 
@@ -26,6 +27,8 @@
 #include <keymasterV4_1/attestation_record.h>
 #include <keymasterV4_1/authorization_set.h>
 
+using android::hardware::keymaster::V4_0::test::add_tag_from_prop;
+
 // Not to dump the attestation by default. Can enable by specify the parameter
 // "--dump_attestations" on lunching VTS
 static bool dumpAttestations = false;
@@ -172,10 +175,42 @@
     attestation.software_enforced.Sort();
     attestation.hardware_enforced.Sort();
 
-    EXPECT_EQ(filter_tags(expected_sw_enforced), filter_tags(attestation.software_enforced))
-            << DIFFERENCE(expected_sw_enforced, attestation.software_enforced);
-    EXPECT_EQ(filter_tags(expected_hw_enforced), filter_tags(attestation.hardware_enforced))
-            << DIFFERENCE(expected_hw_enforced, attestation.hardware_enforced);
+    expected_sw_enforced = filter_tags(expected_sw_enforced);
+    expected_hw_enforced = filter_tags(expected_hw_enforced);
+    AuthorizationSet attestation_sw_enforced = filter_tags(attestation.software_enforced);
+    AuthorizationSet attestation_hw_enforced = filter_tags(attestation.hardware_enforced);
+
+    EXPECT_EQ(expected_sw_enforced, attestation_sw_enforced)
+            << DIFFERENCE(expected_sw_enforced, attestation_sw_enforced);
+    EXPECT_EQ(expected_hw_enforced, attestation_hw_enforced)
+            << DIFFERENCE(expected_hw_enforced, attestation_hw_enforced);
+}
+
+X509_Ptr parse_cert_blob(const std::vector<uint8_t>& blob) {
+    const uint8_t* p = blob.data();
+    return X509_Ptr(d2i_X509(nullptr /* allocate new */, &p, blob.size()));
+}
+
+bool check_certificate_chain_signatures(const hidl_vec<hidl_vec<uint8_t>>& cert_chain) {
+    // TODO: Check that root is self-signed once b/187803288 is resolved.
+    for (size_t i = 0; i < cert_chain.size() - 1; ++i) {
+        X509_Ptr key_cert(parse_cert_blob(cert_chain[i]));
+        X509_Ptr signing_cert(parse_cert_blob(cert_chain[i + 1]));
+
+        if (!key_cert.get() || !signing_cert.get()) {
+            return false;
+        }
+
+        EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
+        if (!signing_pubkey.get()) {
+            return false;
+        }
+
+        if (!X509_verify(key_cert.get(), signing_pubkey.get())) {
+            return false;
+        }
+    }
+    return true;
 }
 
 }  // namespace
@@ -243,6 +278,7 @@
 
     EXPECT_EQ(ErrorCode::OK, result);
     EXPECT_EQ(2U, cert_chain.size());
+    EXPECT_TRUE(check_certificate_chain_signatures(cert_chain));
     if (dumpAttestations) {
       for (auto cert_ : cert_chain) dumpContent(bin2hex(cert_));
     }
@@ -289,6 +325,7 @@
 
     EXPECT_EQ(ErrorCode::OK, result);
     EXPECT_EQ(2U, cert_chain.size());
+    EXPECT_TRUE(check_certificate_chain_signatures(cert_chain));
     if (dumpAttestations) {
       for (auto cert_ : cert_chain) dumpContent(bin2hex(cert_));
     }
@@ -312,6 +349,106 @@
             SecLevel());
 }
 
+TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestationID) {
+    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_INCLUDE_UNIQUE_ID))));
+
+    // Collection of valid attestation ID tags.
+    auto attestation_id_tags = AuthorizationSetBuilder();
+    add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
+    add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
+    add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
+    add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+    add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_MANUFACTURER,
+                      "ro.product.manufacturer");
+    add_tag_from_prop(&attestation_id_tags, V4_0::TAG_ATTESTATION_ID_MODEL, "ro.product.model");
+
+    for (const KeyParameter& tag : attestation_id_tags) {
+        hidl_vec<hidl_vec<uint8_t>> cert_chain;
+        HidlBuf challenge("challenge");
+        HidlBuf app_id("foo");
+        AuthorizationSetBuilder builder =
+                AuthorizationSetBuilder()
+                        .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+                        .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
+                        .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id);
+        builder.push_back(tag);
+        ErrorCode result = convert(AttestKey(builder, &cert_chain));
+
+        // It is optional for Strong box to support DeviceUniqueAttestation.
+        if (result == ErrorCode::CANNOT_ATTEST_IDS) return;
+
+        ASSERT_EQ(ErrorCode::OK, result);
+        EXPECT_EQ(2U, cert_chain.size());
+        if (dumpAttestations) {
+            for (auto cert_ : cert_chain) dumpContent(bin2hex(cert_));
+        }
+        auto [err, attestation] = parse_attestation_record(cert_chain[0]);
+        ASSERT_EQ(ErrorCode::OK, err);
+
+        AuthorizationSetBuilder hw_enforced =
+                AuthorizationSetBuilder()
+                        .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+                        .Authorization(TAG_NO_AUTH_REQUIRED)
+                        .EcdsaSigningKey(256)
+                        .Digest(Digest::SHA_2_256)
+                        .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
+                        .Authorization(TAG_OS_VERSION, os_version())
+                        .Authorization(TAG_OS_PATCHLEVEL, os_patch_level());
+        hw_enforced.push_back(tag);
+        check_attestation_record(
+                attestation, challenge,
+                /* sw_enforced */
+                AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id),
+                hw_enforced, SecLevel());
+    }
+}
+
+TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestationMismatchID) {
+    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_INCLUDE_UNIQUE_ID))));
+
+    // Collection of invalid attestation ID tags.
+    std::string invalid = "completely-invalid";
+    auto attestation_id_tags =
+            AuthorizationSetBuilder()
+                    .Authorization(V4_0::TAG_ATTESTATION_ID_BRAND, invalid.data(), invalid.size())
+                    .Authorization(V4_0::TAG_ATTESTATION_ID_DEVICE, invalid.data(), invalid.size())
+                    .Authorization(V4_0::TAG_ATTESTATION_ID_PRODUCT, invalid.data(), invalid.size())
+                    .Authorization(V4_0::TAG_ATTESTATION_ID_SERIAL, invalid.data(), invalid.size())
+                    .Authorization(V4_0::TAG_ATTESTATION_ID_IMEI, invalid.data(), invalid.size())
+                    .Authorization(V4_0::TAG_ATTESTATION_ID_MEID, invalid.data(), invalid.size())
+                    .Authorization(V4_0::TAG_ATTESTATION_ID_MANUFACTURER, invalid.data(),
+                                   invalid.size())
+                    .Authorization(V4_0::TAG_ATTESTATION_ID_MODEL, invalid.data(), invalid.size());
+
+    for (const KeyParameter& invalid_tag : attestation_id_tags) {
+        hidl_vec<hidl_vec<uint8_t>> cert_chain;
+        HidlBuf challenge("challenge");
+        HidlBuf app_id("foo");
+        AuthorizationSetBuilder builder =
+                AuthorizationSetBuilder()
+                        .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+                        .Authorization(TAG_ATTESTATION_CHALLENGE, challenge)
+                        .Authorization(TAG_ATTESTATION_APPLICATION_ID, app_id);
+        builder.push_back(invalid_tag);
+        ErrorCode result = convert(AttestKey(builder, &cert_chain));
+
+        EXPECT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG)
+                << "result: " << static_cast<int32_t>(result);
+    }
+}
+
 INSTANTIATE_KEYMASTER_4_1_HIDL_TEST(DeviceUniqueAttestationTest);
 
 }  // namespace test
diff --git a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
index f8c1fad..670ccfb 100644
--- a/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
+++ b/keymaster/4.1/vts/functional/Keymaster4_1HidlTest.h
@@ -18,6 +18,8 @@
 
 #include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
 
+#include <android-base/properties.h>
+
 #include <KeymasterHidlTest.h>
 #include <keymasterV4_1/authorization_set.h>
 
@@ -159,3 +161,17 @@
                              android::hardware::PrintInstanceNameToString)
 
 }  // namespace android::hardware::keymaster::V4_1::test
+
+namespace android::hardware::keymaster::V4_0::test {
+
+// If the given property is available, add it to the tag set under the given tag ID.
+template <Tag tag>
+void add_tag_from_prop(AuthorizationSetBuilder* tags, TypedTag<TagType::BYTES, tag> ttag,
+                       const char* prop) {
+    std::string prop_value = ::android::base::GetProperty(prop, /* default= */ "");
+    if (!prop_value.empty()) {
+        tags->Authorization(ttag, prop_value.data(), prop_value.size());
+    }
+}
+
+}  // namespace android::hardware::keymaster::V4_0::test
diff --git a/neuralnetworks/1.3/utils/src/Conversions.cpp b/neuralnetworks/1.3/utils/src/Conversions.cpp
index e8a4f55..11225cf 100644
--- a/neuralnetworks/1.3/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.3/utils/src/Conversions.cpp
@@ -239,7 +239,7 @@
     using Discriminator = hal::V1_3::Request::MemoryPool::hidl_discriminator;
     switch (memoryPool.getDiscriminator()) {
         case Discriminator::hidlMemory:
-            return hal::utils::createSharedMemoryFromHidlMemory(memoryPool.hidlMemory());
+            return unvalidatedConvert(memoryPool.hidlMemory());
         case Discriminator::token:
             return static_cast<Request::MemoryDomainToken>(memoryPool.token());
     }
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
index 5eab9ff..78433a7 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
@@ -95,9 +95,7 @@
 GeneralResult<Extension> unvalidatedConvert(const aidl_hal::Extension& extension);
 GeneralResult<Extension::OperandTypeInformation> unvalidatedConvert(
         const aidl_hal::ExtensionOperandTypeInformation& operandTypeInformation);
-GeneralResult<SharedHandle> unvalidatedConvert(
-        const ::aidl::android::hardware::common::NativeHandle& handle);
-GeneralResult<SyncFence> unvalidatedConvert(const ndk::ScopedFileDescriptor& syncFence);
+GeneralResult<SharedHandle> unvalidatedConvert(const ndk::ScopedFileDescriptor& handle);
 
 GeneralResult<std::vector<Operation>> unvalidatedConvert(
         const std::vector<aidl_hal::Operation>& operations);
@@ -113,7 +111,7 @@
 GeneralResult<Priority> convert(const aidl_hal::Priority& priority);
 GeneralResult<Request> convert(const aidl_hal::Request& request);
 GeneralResult<Timing> convert(const aidl_hal::Timing& timing);
-GeneralResult<SyncFence> convert(const ndk::ScopedFileDescriptor& syncFence);
+GeneralResult<SharedHandle> convert(const ndk::ScopedFileDescriptor& handle);
 
 GeneralResult<std::vector<Extension>> convert(const std::vector<aidl_hal::Extension>& extension);
 GeneralResult<std::vector<SharedMemory>> convert(const std::vector<aidl_hal::Memory>& memories);
@@ -160,9 +158,7 @@
 nn::GeneralResult<int64_t> unvalidatedConvert(const nn::OptionalDuration& optionalDuration);
 nn::GeneralResult<int64_t> unvalidatedConvert(const nn::OptionalTimePoint& optionalTimePoint);
 nn::GeneralResult<ndk::ScopedFileDescriptor> unvalidatedConvert(const nn::SyncFence& syncFence);
-nn::GeneralResult<common::NativeHandle> unvalidatedConvert(const nn::SharedHandle& sharedHandle);
-nn::GeneralResult<ndk::ScopedFileDescriptor> unvalidatedConvertCache(
-        const nn::SharedHandle& handle);
+nn::GeneralResult<ndk::ScopedFileDescriptor> unvalidatedConvert(const nn::SharedHandle& handle);
 
 nn::GeneralResult<std::vector<uint8_t>> convert(const nn::CacheToken& cacheToken);
 nn::GeneralResult<BufferDesc> convert(const nn::BufferDesc& bufferDesc);
diff --git a/neuralnetworks/aidl/utils/src/Burst.cpp b/neuralnetworks/aidl/utils/src/Burst.cpp
index 87cd0e4..800ac32 100644
--- a/neuralnetworks/aidl/utils/src/Burst.cpp
+++ b/neuralnetworks/aidl/utils/src/Burst.cpp
@@ -62,7 +62,7 @@
   private:
     const std::shared_ptr<const Burst> kBurst;
     const Request kRequest;
-    const std::vector<int64_t>& kMemoryIdentifierTokens;
+    const std::vector<int64_t> kMemoryIdentifierTokens;
     const bool kMeasure;
     const int64_t kLoopTimeoutDuration;
     const hal::utils::RequestRelocation kRelocation;
diff --git a/neuralnetworks/aidl/utils/src/Conversions.cpp b/neuralnetworks/aidl/utils/src/Conversions.cpp
index 4b263ee..0517730 100644
--- a/neuralnetworks/aidl/utils/src/Conversions.cpp
+++ b/neuralnetworks/aidl/utils/src/Conversions.cpp
@@ -108,17 +108,6 @@
     return canonical;
 }
 
-GeneralResult<Handle> unvalidatedConvertHelper(const NativeHandle& aidlNativeHandle) {
-    std::vector<base::unique_fd> fds;
-    fds.reserve(aidlNativeHandle.fds.size());
-    for (const auto& fd : aidlNativeHandle.fds) {
-        auto duplicatedFd = NN_TRY(dupFd(fd.get()));
-        fds.emplace_back(duplicatedFd.release());
-    }
-
-    return Handle{.fds = std::move(fds), .ints = aidlNativeHandle.ints};
-}
-
 struct NativeHandleDeleter {
     void operator()(native_handle_t* handle) const {
         if (handle) {
@@ -498,18 +487,14 @@
     return static_cast<ExecutionPreference>(executionPreference);
 }
 
-GeneralResult<SharedHandle> unvalidatedConvert(const NativeHandle& aidlNativeHandle) {
-    return std::make_shared<const Handle>(NN_TRY(unvalidatedConvertHelper(aidlNativeHandle)));
-}
-
 GeneralResult<std::vector<Operation>> unvalidatedConvert(
         const std::vector<aidl_hal::Operation>& operations) {
     return unvalidatedConvertVec(operations);
 }
 
-GeneralResult<SyncFence> unvalidatedConvert(const ndk::ScopedFileDescriptor& syncFence) {
-    auto duplicatedFd = NN_TRY(dupFd(syncFence.get()));
-    return SyncFence::create(std::move(duplicatedFd));
+GeneralResult<SharedHandle> unvalidatedConvert(const ndk::ScopedFileDescriptor& handle) {
+    auto duplicatedFd = NN_TRY(dupFd(handle.get()));
+    return std::make_shared<const Handle>(std::move(duplicatedFd));
 }
 
 GeneralResult<Capabilities> convert(const aidl_hal::Capabilities& capabilities) {
@@ -553,8 +538,8 @@
     return validatedConvert(timing);
 }
 
-GeneralResult<SyncFence> convert(const ndk::ScopedFileDescriptor& syncFence) {
-    return validatedConvert(syncFence);
+GeneralResult<SharedHandle> convert(const ndk::ScopedFileDescriptor& handle) {
+    return validatedConvert(handle);
 }
 
 GeneralResult<std::vector<Extension>> convert(const std::vector<aidl_hal::Extension>& extension) {
@@ -619,17 +604,6 @@
     return halObject;
 }
 
-nn::GeneralResult<common::NativeHandle> unvalidatedConvert(const nn::Handle& handle) {
-    common::NativeHandle aidlNativeHandle;
-    aidlNativeHandle.fds.reserve(handle.fds.size());
-    for (const auto& fd : handle.fds) {
-        auto duplicatedFd = NN_TRY(nn::dupFd(fd.get()));
-        aidlNativeHandle.fds.emplace_back(duplicatedFd.release());
-    }
-    aidlNativeHandle.ints = handle.ints;
-    return aidlNativeHandle;
-}
-
 // Helper template for std::visit
 template <class... Ts>
 struct overloaded : Ts... {
@@ -755,11 +729,6 @@
     return measureTiming == nn::MeasureTiming::YES;
 }
 
-nn::GeneralResult<common::NativeHandle> unvalidatedConvert(const nn::SharedHandle& sharedHandle) {
-    CHECK(sharedHandle != nullptr);
-    return unvalidatedConvert(*sharedHandle);
-}
-
 nn::GeneralResult<Memory> unvalidatedConvert(const nn::SharedMemory& memory) {
     if (memory == nullptr) {
         return (NN_ERROR() << "Unable to convert nullptr memory")
@@ -997,16 +966,8 @@
     return ndk::ScopedFileDescriptor(duplicatedFd.release());
 }
 
-nn::GeneralResult<ndk::ScopedFileDescriptor> unvalidatedConvertCache(
-        const nn::SharedHandle& handle) {
-    if (handle->ints.size() != 0) {
-        NN_ERROR() << "Cache handle must not contain ints";
-    }
-    if (handle->fds.size() != 1) {
-        NN_ERROR() << "Cache handle must contain exactly one fd but contains "
-                   << handle->fds.size();
-    }
-    auto duplicatedFd = NN_TRY(nn::dupFd(handle->fds.front().get()));
+nn::GeneralResult<ndk::ScopedFileDescriptor> unvalidatedConvert(const nn::SharedHandle& handle) {
+    auto duplicatedFd = NN_TRY(nn::dupFd(handle->get()));
     return ndk::ScopedFileDescriptor(duplicatedFd.release());
 }
 
@@ -1069,16 +1030,7 @@
 
 nn::GeneralResult<std::vector<ndk::ScopedFileDescriptor>> convert(
         const std::vector<nn::SharedHandle>& cacheHandles) {
-    const auto version = NN_TRY(hal::utils::makeGeneralFailure(nn::validate(cacheHandles)));
-    if (version > kVersion) {
-        return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
-    }
-    std::vector<ndk::ScopedFileDescriptor> cacheFds;
-    cacheFds.reserve(cacheHandles.size());
-    for (const auto& cacheHandle : cacheHandles) {
-        cacheFds.push_back(NN_TRY(unvalidatedConvertCache(cacheHandle)));
-    }
-    return cacheFds;
+    return validatedConvert(cacheHandles);
 }
 
 nn::GeneralResult<std::vector<ndk::ScopedFileDescriptor>> convert(
diff --git a/neuralnetworks/aidl/utils/src/PreparedModel.cpp b/neuralnetworks/aidl/utils/src/PreparedModel.cpp
index 18e7636..f861d74 100644
--- a/neuralnetworks/aidl/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/aidl/utils/src/PreparedModel.cpp
@@ -160,7 +160,7 @@
 
     auto resultSyncFence = nn::SyncFence::createAsSignaled();
     if (result.syncFence.get() != -1) {
-        resultSyncFence = NN_TRY(nn::convert(result.syncFence));
+        resultSyncFence = nn::SyncFence::create(NN_TRY(nn::convert(result.syncFence))).value();
     }
 
     auto callback = result.callback;
diff --git a/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
index e0b529f..94ce5c1 100644
--- a/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
@@ -357,16 +357,40 @@
         return false;
     }
 
+    // If fallbackModel is not provided, call prepareModelFromCache.
+    // If fallbackModel is provided, and prepareModelFromCache returns GENERAL_FAILURE,
+    // then prepareModel(fallbackModel) will be called.
+    // This replicates the behaviour of the runtime when loading a model from cache.
+    // NNAPI Shim depends on this behaviour and may try to load the model from cache in
+    // prepareModel (shim needs model information when loading from cache).
     void prepareModelFromCache(const std::vector<ndk::ScopedFileDescriptor>& modelCache,
                                const std::vector<ndk::ScopedFileDescriptor>& dataCache,
-                               std::shared_ptr<IPreparedModel>* preparedModel,
-                               ErrorStatus* status) {
+                               std::shared_ptr<IPreparedModel>* preparedModel, ErrorStatus* status,
+                               const Model* fallbackModel = nullptr) {
         // Launch prepare model from cache.
         std::shared_ptr<PreparedModelCallback> preparedModelCallback =
                 ndk::SharedRefBase::make<PreparedModelCallback>();
         std::vector<uint8_t> cacheToken(std::begin(mToken), std::end(mToken));
-        const auto prepareLaunchStatus = kDevice->prepareModelFromCache(
+        auto prepareLaunchStatus = kDevice->prepareModelFromCache(
                 kNoDeadline, modelCache, dataCache, cacheToken, preparedModelCallback);
+
+        // The shim does not support prepareModelFromCache() properly, but it
+        // will still attempt to create a model from cache when modelCache or
+        // dataCache is provided in prepareModel(). Instead of failing straight
+        // away, we try to utilize that other code path when fallbackModel is
+        // set. Note that we cannot verify whether the returned model was
+        // actually prepared from cache in that case.
+        if (!prepareLaunchStatus.isOk() &&
+            prepareLaunchStatus.getExceptionCode() == EX_SERVICE_SPECIFIC &&
+            static_cast<ErrorStatus>(prepareLaunchStatus.getServiceSpecificError()) ==
+                    ErrorStatus::GENERAL_FAILURE &&
+            mIsCachingSupported && fallbackModel != nullptr) {
+            preparedModelCallback = ndk::SharedRefBase::make<PreparedModelCallback>();
+            prepareLaunchStatus = kDevice->prepareModel(
+                    *fallbackModel, ExecutionPreference::FAST_SINGLE_ANSWER, kDefaultPriority,
+                    kNoDeadline, modelCache, dataCache, cacheToken, preparedModelCallback);
+        }
+
         ASSERT_TRUE(prepareLaunchStatus.isOk() ||
                     prepareLaunchStatus.getExceptionCode() == EX_SERVICE_SPECIFIC)
                 << "prepareLaunchStatus: " << prepareLaunchStatus.getDescription();
@@ -382,6 +406,42 @@
         *preparedModel = preparedModelCallback->getPreparedModel();
     }
 
+    // Replicate behaviour of runtime when loading model from cache.
+    // Test if prepareModelFromCache behaves correctly when faced with bad
+    // arguments. If prepareModelFromCache is not supported (GENERAL_FAILURE),
+    // it attempts to call prepareModel with same arguments, which is expected either
+    // to not support the model (GENERAL_FAILURE) or return a valid model.
+    void verifyModelPreparationBehaviour(const std::vector<ndk::ScopedFileDescriptor>& modelCache,
+                                         const std::vector<ndk::ScopedFileDescriptor>& dataCache,
+                                         const Model* model, const TestModel& testModel) {
+        std::shared_ptr<IPreparedModel> preparedModel;
+        ErrorStatus status;
+
+        // Verify that prepareModelFromCache fails either due to bad
+        // arguments (INVALID_ARGUMENT) or GENERAL_FAILURE if not supported.
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status,
+                              /*fallbackModel=*/nullptr);
+        if (status != ErrorStatus::INVALID_ARGUMENT) {
+            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
+        }
+        ASSERT_EQ(preparedModel, nullptr);
+
+        // If caching is not supported, attempt calling prepareModel.
+        if (status == ErrorStatus::GENERAL_FAILURE) {
+            // Fallback with prepareModel should succeed regardless of cache files
+            prepareModelFromCache(modelCache, dataCache, &preparedModel, &status,
+                                  /*fallbackModel=*/model);
+            // Unless caching is not supported?
+            if (status != ErrorStatus::GENERAL_FAILURE) {
+                // But if it is, we should see a valid model.
+                ASSERT_EQ(status, ErrorStatus::NONE);
+                ASSERT_NE(preparedModel, nullptr);
+                EvaluatePreparedModel(kDevice, preparedModel, testModel,
+                                      /*testKind=*/TestKind::GENERAL);
+            }
+        }
+    }
+
     // Absolute path to the temporary cache directory.
     std::string mCacheDir;
 
@@ -397,7 +457,7 @@
     uint8_t mToken[static_cast<uint32_t>(IDevice::BYTE_SIZE_OF_CACHE_TOKEN)] = {};
     uint32_t mNumModelCache;
     uint32_t mNumDataCache;
-    uint32_t mIsCachingSupported;
+    bool mIsCachingSupported;
 
     const std::shared_ptr<IDevice> kDevice;
     // The primary data type of the testModel.
@@ -438,7 +498,8 @@
         std::vector<ndk::ScopedFileDescriptor> modelCache, dataCache;
         createCacheFds(mModelCache, AccessMode::READ_WRITE, &modelCache);
         createCacheFds(mDataCache, AccessMode::READ_WRITE, &dataCache);
-        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status,
+                              /*fallbackModel=*/&model);
         if (!mIsCachingSupported) {
             ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
             ASSERT_EQ(preparedModel, nullptr);
@@ -498,7 +559,8 @@
         for (uint32_t i = 0; i < dataCache.size(); i++) {
             ASSERT_GE(read(dataCache[i].get(), &placeholderByte, 1), 0);
         }
-        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status,
+                              /*fallbackModel=*/&model);
         if (!mIsCachingSupported) {
             ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
             ASSERT_EQ(preparedModel, nullptr);
@@ -536,13 +598,7 @@
         // Execute and verify results.
         EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
-        preparedModel = nullptr;
-        ErrorStatus status;
-        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
-        if (status != ErrorStatus::INVALID_ARGUMENT) {
-            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-        }
-        ASSERT_EQ(preparedModel, nullptr);
+        verifyModelPreparationBehaviour(modelCache, dataCache, &model, testModel);
     }
 
     // Test with number of model cache files smaller than mNumModelCache.
@@ -560,13 +616,7 @@
         // Execute and verify results.
         EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
-        preparedModel = nullptr;
-        ErrorStatus status;
-        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
-        if (status != ErrorStatus::INVALID_ARGUMENT) {
-            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-        }
-        ASSERT_EQ(preparedModel, nullptr);
+        verifyModelPreparationBehaviour(modelCache, dataCache, &model, testModel);
     }
 
     // Test with number of data cache files greater than mNumDataCache.
@@ -583,13 +633,7 @@
         // Execute and verify results.
         EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
-        preparedModel = nullptr;
-        ErrorStatus status;
-        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
-        if (status != ErrorStatus::INVALID_ARGUMENT) {
-            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-        }
-        ASSERT_EQ(preparedModel, nullptr);
+        verifyModelPreparationBehaviour(modelCache, dataCache, &model, testModel);
     }
 
     // Test with number of data cache files smaller than mNumDataCache.
@@ -607,13 +651,7 @@
         // Execute and verify results.
         EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
-        preparedModel = nullptr;
-        ErrorStatus status;
-        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
-        if (status != ErrorStatus::INVALID_ARGUMENT) {
-            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-        }
-        ASSERT_EQ(preparedModel, nullptr);
+        verifyModelPreparationBehaviour(modelCache, dataCache, &model, testModel);
     }
 }
 
@@ -633,68 +671,48 @@
 
     // Test with number of model cache files greater than mNumModelCache.
     {
-        std::shared_ptr<IPreparedModel> preparedModel = nullptr;
-        ErrorStatus status;
         std::vector<ndk::ScopedFileDescriptor> modelCache, dataCache;
         mModelCache.push_back({mTmpCache});
         createCacheFds(mModelCache, AccessMode::READ_WRITE, &modelCache);
         createCacheFds(mDataCache, AccessMode::READ_WRITE, &dataCache);
         mModelCache.pop_back();
-        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
-        if (status != ErrorStatus::GENERAL_FAILURE) {
-            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
-        }
-        ASSERT_EQ(preparedModel, nullptr);
+
+        verifyModelPreparationBehaviour(modelCache, dataCache, &model, testModel);
     }
 
     // Test with number of model cache files smaller than mNumModelCache.
     if (mModelCache.size() > 0) {
-        std::shared_ptr<IPreparedModel> preparedModel = nullptr;
-        ErrorStatus status;
         std::vector<ndk::ScopedFileDescriptor> modelCache, dataCache;
         auto tmp = mModelCache.back();
         mModelCache.pop_back();
         createCacheFds(mModelCache, AccessMode::READ_WRITE, &modelCache);
         createCacheFds(mDataCache, AccessMode::READ_WRITE, &dataCache);
         mModelCache.push_back(tmp);
-        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
-        if (status != ErrorStatus::GENERAL_FAILURE) {
-            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
-        }
-        ASSERT_EQ(preparedModel, nullptr);
+
+        verifyModelPreparationBehaviour(modelCache, dataCache, &model, testModel);
     }
 
     // Test with number of data cache files greater than mNumDataCache.
     {
-        std::shared_ptr<IPreparedModel> preparedModel = nullptr;
-        ErrorStatus status;
         std::vector<ndk::ScopedFileDescriptor> modelCache, dataCache;
         mDataCache.push_back({mTmpCache});
         createCacheFds(mModelCache, AccessMode::READ_WRITE, &modelCache);
         createCacheFds(mDataCache, AccessMode::READ_WRITE, &dataCache);
         mDataCache.pop_back();
-        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
-        if (status != ErrorStatus::GENERAL_FAILURE) {
-            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
-        }
-        ASSERT_EQ(preparedModel, nullptr);
+
+        verifyModelPreparationBehaviour(modelCache, dataCache, &model, testModel);
     }
 
     // Test with number of data cache files smaller than mNumDataCache.
     if (mDataCache.size() > 0) {
-        std::shared_ptr<IPreparedModel> preparedModel = nullptr;
-        ErrorStatus status;
         std::vector<ndk::ScopedFileDescriptor> modelCache, dataCache;
         auto tmp = mDataCache.back();
         mDataCache.pop_back();
         createCacheFds(mModelCache, AccessMode::READ_WRITE, &modelCache);
         createCacheFds(mDataCache, AccessMode::READ_WRITE, &dataCache);
         mDataCache.push_back(tmp);
-        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
-        if (status != ErrorStatus::GENERAL_FAILURE) {
-            ASSERT_EQ(status, ErrorStatus::INVALID_ARGUMENT);
-        }
-        ASSERT_EQ(preparedModel, nullptr);
+
+        verifyModelPreparationBehaviour(modelCache, dataCache, &model, testModel);
     }
 }
 
@@ -719,13 +737,7 @@
         // Execute and verify results.
         EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
-        preparedModel = nullptr;
-        ErrorStatus status;
-        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
-        if (status != ErrorStatus::INVALID_ARGUMENT) {
-            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-        }
-        ASSERT_EQ(preparedModel, nullptr);
+        verifyModelPreparationBehaviour(modelCache, dataCache, &model, testModel);
     }
 
     // Go through each handle in data cache, test with invalid access mode.
@@ -741,13 +753,7 @@
         // Execute and verify results.
         EvaluatePreparedModel(kDevice, preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
-        preparedModel = nullptr;
-        ErrorStatus status;
-        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
-        if (status != ErrorStatus::INVALID_ARGUMENT) {
-            ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-        }
-        ASSERT_EQ(preparedModel, nullptr);
+        verifyModelPreparationBehaviour(modelCache, dataCache, &model, testModel);
     }
 }
 
@@ -769,30 +775,23 @@
 
     // Go through each handle in model cache, test with invalid access mode.
     for (uint32_t i = 0; i < mNumModelCache; i++) {
-        std::shared_ptr<IPreparedModel> preparedModel = nullptr;
-        ErrorStatus status;
         std::vector<ndk::ScopedFileDescriptor> modelCache, dataCache;
         modelCacheMode[i] = AccessMode::WRITE_ONLY;
         createCacheFds(mModelCache, modelCacheMode, &modelCache);
         createCacheFds(mDataCache, dataCacheMode, &dataCache);
         modelCacheMode[i] = AccessMode::READ_WRITE;
-        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
-        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-        ASSERT_EQ(preparedModel, nullptr);
+
+        verifyModelPreparationBehaviour(modelCache, dataCache, &model, testModel);
     }
 
     // Go through each handle in data cache, test with invalid access mode.
     for (uint32_t i = 0; i < mNumDataCache; i++) {
-        std::shared_ptr<IPreparedModel> preparedModel = nullptr;
-        ErrorStatus status;
         std::vector<ndk::ScopedFileDescriptor> modelCache, dataCache;
         dataCacheMode[i] = AccessMode::WRITE_ONLY;
         createCacheFds(mModelCache, modelCacheMode, &modelCache);
         createCacheFds(mDataCache, dataCacheMode, &dataCache);
         dataCacheMode[i] = AccessMode::READ_WRITE;
-        prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
-        ASSERT_EQ(status, ErrorStatus::GENERAL_FAILURE);
-        ASSERT_EQ(preparedModel, nullptr);
+        verifyModelPreparationBehaviour(modelCache, dataCache, &model, testModel);
     }
 }
 
@@ -872,7 +871,8 @@
             std::vector<ndk::ScopedFileDescriptor> modelCache, dataCache;
             createCacheFds(mModelCache, AccessMode::READ_WRITE, &modelCache);
             createCacheFds(mDataCache, AccessMode::READ_WRITE, &dataCache);
-            prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+            prepareModelFromCache(modelCache, dataCache, &preparedModel, &status,
+                                  /*fallbackModel=*/nullptr);
 
             // The preparation may fail or succeed, but must not crash. If the preparation succeeds,
             // the prepared model must be executed with the correct result and not crash.
@@ -933,7 +933,8 @@
 
             // Spawn a thread to copy the cache content concurrently while preparing from cache.
             std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache));
-            prepareModelFromCache(modelCache, dataCache, &preparedModel, &status);
+            prepareModelFromCache(modelCache, dataCache, &preparedModel, &status,
+                                  /*fallbackModel=*/nullptr);
             thread.join();
 
             // The preparation may fail or succeed, but must not crash. If the preparation succeeds,
diff --git a/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
index d3b041d..2356ff0 100644
--- a/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
@@ -435,8 +435,8 @@
         mInputMemory = TestBlobAHWB::create(std::max<size_t>(inputSize, 1));
         mOutputMemory = TestBlobAHWB::create(std::max<size_t>(outputSize, 1));
     } else {
-        mInputMemory = TestAshmem::create(std::max<size_t>(inputSize, 1));
-        mOutputMemory = TestAshmem::create(std::max<size_t>(outputSize, 1));
+        mInputMemory = TestAshmem::create(std::max<size_t>(inputSize, 1), /*aidlReadonly=*/true);
+        mOutputMemory = TestAshmem::create(std::max<size_t>(outputSize, 1), /*aidlReadonly=*/false);
     }
     CHECK_NE(mInputMemory, nullptr);
     CHECK_NE(mOutputMemory, nullptr);
diff --git a/neuralnetworks/aidl/vts/functional/Utils.cpp b/neuralnetworks/aidl/vts/functional/Utils.cpp
index 3c7f5f7..9af362e 100644
--- a/neuralnetworks/aidl/vts/functional/Utils.cpp
+++ b/neuralnetworks/aidl/vts/functional/Utils.cpp
@@ -23,6 +23,7 @@
 #include <android/binder_status.h>
 #include <android/hardware_buffer.h>
 
+#include <sys/mman.h>
 #include <iostream>
 #include <limits>
 #include <numeric>
@@ -98,19 +99,39 @@
                            std::multiplies<>{});
 }
 
-std::unique_ptr<TestAshmem> TestAshmem::create(uint32_t size) {
-    auto ashmem = std::make_unique<TestAshmem>(size);
+std::unique_ptr<TestAshmem> TestAshmem::create(uint32_t size, bool aidlReadonly) {
+    auto ashmem = std::make_unique<TestAshmem>(size, aidlReadonly);
     return ashmem->mIsValid ? std::move(ashmem) : nullptr;
 }
 
-void TestAshmem::initialize(uint32_t size) {
+// This function will create a readonly shared memory with PROT_READ only.
+// The input shared memory must be either Ashmem or mapped-FD.
+static nn::SharedMemory convertSharedMemoryToReadonly(const nn::SharedMemory& sharedMemory) {
+    if (std::holds_alternative<nn::Memory::Ashmem>(sharedMemory->handle)) {
+        const auto& memory = std::get<nn::Memory::Ashmem>(sharedMemory->handle);
+        return nn::createSharedMemoryFromFd(memory.size, PROT_READ, memory.fd.get(), /*offset=*/0)
+                .value();
+    } else if (std::holds_alternative<nn::Memory::Fd>(sharedMemory->handle)) {
+        const auto& memory = std::get<nn::Memory::Fd>(sharedMemory->handle);
+        return nn::createSharedMemoryFromFd(memory.size, PROT_READ, memory.fd.get(), memory.offset)
+                .value();
+    }
+    CHECK(false) << "Unexpected shared memory type";
+    return sharedMemory;
+}
+
+void TestAshmem::initialize(uint32_t size, bool aidlReadonly) {
     mIsValid = false;
     ASSERT_GT(size, 0);
     const auto sharedMemory = nn::createSharedMemory(size).value();
     mMappedMemory = nn::map(sharedMemory).value();
     mPtr = static_cast<uint8_t*>(std::get<void*>(mMappedMemory.pointer));
     CHECK_NE(mPtr, nullptr);
-    mAidlMemory = utils::convert(sharedMemory).value();
+    if (aidlReadonly) {
+        mAidlMemory = utils::convert(convertSharedMemoryToReadonly(sharedMemory)).value();
+    } else {
+        mAidlMemory = utils::convert(sharedMemory).value();
+    }
     mIsValid = true;
 }
 
diff --git a/neuralnetworks/aidl/vts/functional/Utils.h b/neuralnetworks/aidl/vts/functional/Utils.h
index 77085a7..9dd7359 100644
--- a/neuralnetworks/aidl/vts/functional/Utils.h
+++ b/neuralnetworks/aidl/vts/functional/Utils.h
@@ -79,15 +79,18 @@
 
 class TestAshmem : public TestMemoryBase {
   public:
-    static std::unique_ptr<TestAshmem> create(uint32_t size);
+    // If aidlReadonly is true, getAidlMemory will return a sAIDL memory with readonly access;
+    // otherwise, the sAIDL memory has read-write access. This only affects the sAIDL memory.
+    // getPointer will always return a valid address with read-write access.
+    static std::unique_ptr<TestAshmem> create(uint32_t size, bool aidlReadonly = false);
 
     // Prefer TestAshmem::create.
     // The constructor calls initialize, which constructs the memory resources. This is a workaround
     // that gtest macros cannot be used directly in a constructor.
-    TestAshmem(uint32_t size) { initialize(size); }
+    TestAshmem(uint32_t size, bool aidlReadonly) { initialize(size, aidlReadonly); }
 
   private:
-    void initialize(uint32_t size);
+    void initialize(uint32_t size, bool aidlReadonly);
     nn::Mapping mMappedMemory;
 };
 
diff --git a/neuralnetworks/utils/common/src/CommonUtils.cpp b/neuralnetworks/utils/common/src/CommonUtils.cpp
index 8e55bf0..906b0cf 100644
--- a/neuralnetworks/utils/common/src/CommonUtils.cpp
+++ b/neuralnetworks/utils/common/src/CommonUtils.cpp
@@ -89,23 +89,39 @@
                   });
 }
 
-nn::GeneralResult<hidl_handle> createNativeHandleFrom(base::unique_fd fd,
+nn::GeneralResult<hidl_handle> createNativeHandleFrom(std::vector<base::unique_fd> fds,
                                                       const std::vector<int32_t>& ints) {
     constexpr size_t kIntMax = std::numeric_limits<int>::max();
+    CHECK_LE(fds.size(), kIntMax);
     CHECK_LE(ints.size(), kIntMax);
-    native_handle_t* nativeHandle = native_handle_create(1, static_cast<int>(ints.size()));
+    native_handle_t* nativeHandle =
+            native_handle_create(static_cast<int>(fds.size()), static_cast<int>(ints.size()));
     if (nativeHandle == nullptr) {
         return NN_ERROR() << "Failed to create native_handle";
     }
 
-    nativeHandle->data[0] = fd.release();
-    std::copy(ints.begin(), ints.end(), nativeHandle->data + 1);
+    for (size_t i = 0; i < fds.size(); ++i) {
+        nativeHandle->data[i] = fds[i].release();
+    }
+    std::copy(ints.begin(), ints.end(), nativeHandle->data + nativeHandle->numFds);
 
     hidl_handle handle;
     handle.setTo(nativeHandle, /*shouldOwn=*/true);
     return handle;
 }
 
+nn::GeneralResult<hidl_handle> createNativeHandleFrom(base::unique_fd fd,
+                                                      const std::vector<int32_t>& ints) {
+    std::vector<base::unique_fd> fds;
+    fds.push_back(std::move(fd));
+    return createNativeHandleFrom(std::move(fds), ints);
+}
+
+nn::GeneralResult<hidl_handle> createNativeHandleFrom(const nn::Memory::Unknown::Handle& handle) {
+    std::vector<base::unique_fd> fds = NN_TRY(nn::dupFds(handle.fds.begin(), handle.fds.end()));
+    return createNativeHandleFrom(std::move(fds), handle.ints);
+}
+
 nn::GeneralResult<hidl_memory> createHidlMemoryFrom(const nn::Memory::Ashmem& memory) {
     auto fd = NN_TRY(nn::dupFd(memory.fd));
     auto handle = NN_TRY(createNativeHandleFrom(std::move(fd), {}));
@@ -139,7 +155,22 @@
 }
 
 nn::GeneralResult<hidl_memory> createHidlMemoryFrom(const nn::Memory::Unknown& memory) {
-    return hidl_memory(memory.name, NN_TRY(hidlHandleFromSharedHandle(memory.handle)), memory.size);
+    return hidl_memory(memory.name, NN_TRY(createNativeHandleFrom(memory.handle)), memory.size);
+}
+
+nn::GeneralResult<nn::Memory::Unknown::Handle> unknownHandleFromNativeHandle(
+        const native_handle_t* handle) {
+    if (handle == nullptr) {
+        return NN_ERROR() << "unknownHandleFromNativeHandle failed because handle is nullptr";
+    }
+
+    std::vector<base::unique_fd> fds =
+            NN_TRY(nn::dupFds(handle->data + 0, handle->data + handle->numFds));
+
+    std::vector<int> ints(handle->data + handle->numFds,
+                          handle->data + handle->numFds + handle->numInts);
+
+    return nn::Memory::Unknown::Handle{.fds = std::move(fds), .ints = std::move(ints)};
 }
 
 }  // anonymous namespace
@@ -349,7 +380,7 @@
 
     if (memory.name() != "hardware_buffer_blob") {
         auto handle = nn::Memory::Unknown{
-                .handle = NN_TRY(sharedHandleFromNativeHandle(memory.handle())),
+                .handle = NN_TRY(unknownHandleFromNativeHandle(memory.handle())),
                 .size = static_cast<size_t>(memory.size()),
                 .name = memory.name(),
         };
@@ -395,53 +426,19 @@
 }
 
 nn::GeneralResult<hidl_handle> hidlHandleFromSharedHandle(const nn::Handle& handle) {
-    std::vector<base::unique_fd> fds;
-    fds.reserve(handle.fds.size());
-    for (const auto& fd : handle.fds) {
-        const int dupFd = dup(fd);
-        if (dupFd == -1) {
-            return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd";
-        }
-        fds.emplace_back(dupFd);
-    }
-
-    constexpr size_t kIntMax = std::numeric_limits<int>::max();
-    CHECK_LE(handle.fds.size(), kIntMax);
-    CHECK_LE(handle.ints.size(), kIntMax);
-    native_handle_t* nativeHandle = native_handle_create(static_cast<int>(handle.fds.size()),
-                                                         static_cast<int>(handle.ints.size()));
-    if (nativeHandle == nullptr) {
-        return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to create native_handle";
-    }
-    for (size_t i = 0; i < fds.size(); ++i) {
-        nativeHandle->data[i] = fds[i].release();
-    }
-    std::copy(handle.ints.begin(), handle.ints.end(), &nativeHandle->data[nativeHandle->numFds]);
-
-    hidl_handle hidlHandle;
-    hidlHandle.setTo(nativeHandle, /*shouldOwn=*/true);
-    return hidlHandle;
+    base::unique_fd fd = NN_TRY(nn::dupFd(handle.get()));
+    return createNativeHandleFrom(std::move(fd), {});
 }
 
 nn::GeneralResult<nn::Handle> sharedHandleFromNativeHandle(const native_handle_t* handle) {
     if (handle == nullptr) {
         return NN_ERROR() << "sharedHandleFromNativeHandle failed because handle is nullptr";
     }
-
-    std::vector<base::unique_fd> fds;
-    fds.reserve(handle->numFds);
-    for (int i = 0; i < handle->numFds; ++i) {
-        const int dupFd = dup(handle->data[i]);
-        if (dupFd == -1) {
-            return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd";
-        }
-        fds.emplace_back(dupFd);
+    if (handle->numFds != 1 || handle->numInts != 0) {
+        return NN_ERROR() << "sharedHandleFromNativeHandle failed because handle does not only "
+                             "hold a single fd";
     }
-
-    std::vector<int> ints(&handle->data[handle->numFds],
-                          &handle->data[handle->numFds + handle->numInts]);
-
-    return nn::Handle{.fds = std::move(fds), .ints = std::move(ints)};
+    return nn::dupFd(handle->data[0]);
 }
 
 nn::GeneralResult<hidl_vec<hidl_handle>> convertSyncFences(
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
index 422e91c..391166b 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
@@ -19,6 +19,82 @@
 #define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
 
 /*
+ * Test IRadio.setAllowedNetworkTypesBitmap for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, setAllowedNetworkTypesBitmap) {
+    serial = GetRandomSerialNumber();
+    ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_4::RadioAccessFamily>
+            allowedNetworkTypesBitmap{};
+    allowedNetworkTypesBitmap |= ::android::hardware::radio::V1_4::RadioAccessFamily::LTE;
+
+    radio_v1_6->setAllowedNetworkTypesBitmap(serial, allowedNetworkTypesBitmap);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+
+    if (getRadioHalCapabilities()) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_v1_6->rspInfo.error,
+                {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
+    } else {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_v1_6->rspInfo.error,
+                {::android::hardware::radio::V1_6::RadioError::NONE,
+                 ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+                 ::android::hardware::radio::V1_6::RadioError::OPERATION_NOT_ALLOWED,
+                 ::android::hardware::radio::V1_6::RadioError::MODE_NOT_SUPPORTED,
+                 ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
+                 ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+                 ::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
+                 ::android::hardware::radio::V1_6::RadioError::NO_RESOURCES}));
+    }
+}
+
+/*
+ * Test IRadio.getAllowedNetworkTypesBitmap for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, getAllowedNetworkTypesBitmap) {
+    serial = GetRandomSerialNumber();
+    ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_4::RadioAccessFamily>
+            allowedNetworkTypesBitmap{};
+    allowedNetworkTypesBitmap |= ::android::hardware::radio::V1_4::RadioAccessFamily::LTE;
+
+    radio_v1_6->setAllowedNetworkTypesBitmap(serial, allowedNetworkTypesBitmap);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+
+    if (radioRsp_v1_6->rspInfo.error == ::android::hardware::radio::V1_6::RadioError::NONE) {
+        sleep(3);  // wait for modem
+        serial = GetRandomSerialNumber();
+        radio_v1_6->getAllowedNetworkTypesBitmap(serial);
+
+        EXPECT_EQ(std::cv_status::no_timeout, wait());
+        EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+        EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+
+        if (getRadioHalCapabilities()) {
+            ASSERT_TRUE(CheckAnyOfErrors(
+                    radioRsp_v1_6->rspInfo.error,
+                    {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
+        } else {
+            ASSERT_TRUE(CheckAnyOfErrors(
+                    radioRsp_v1_6->rspInfo.error,
+                    {::android::hardware::radio::V1_6::RadioError::NONE,
+                     ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+                     ::android::hardware::radio::V1_6::RadioError::OPERATION_NOT_ALLOWED,
+                     ::android::hardware::radio::V1_6::RadioError::MODE_NOT_SUPPORTED,
+                     ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
+                     ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+                     ::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
+                     ::android::hardware::radio::V1_6::RadioError::NO_RESOURCES}));
+        }
+    }
+}
+
+/*
  * Test IRadio.setupDataCall_1_6() for the response returned.
  */
 TEST_P(RadioHidlTest_v1_6, setupDataCall_1_6) {
@@ -512,11 +588,11 @@
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
-    ASSERT_TRUE(
-            CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
-                             {::android::hardware::radio::V1_6::RadioError::NONE,
-                              ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
-                              ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE}));
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+                                 {::android::hardware::radio::V1_6::RadioError::NONE,
+                                  ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+                                  ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+                                  ::android::hardware::radio::V1_6::RadioError::SIM_ERR}));
 
     // setSimCardPower_1_6 does not return  until the request is handled, and should not trigger
     // CardState::ABSENT when turning off power
@@ -534,11 +610,11 @@
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
-    ASSERT_TRUE(
-            CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
-                             {::android::hardware::radio::V1_6::RadioError::NONE,
-                              ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
-                              ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE}));
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+                                 {::android::hardware::radio::V1_6::RadioError::NONE,
+                                  ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+                                  ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+                                  ::android::hardware::radio::V1_6::RadioError::SIM_ERR}));
 
     // setSimCardPower_1_6 does not return  until the request is handled. Just verify that we still
     // have CardState::PRESENT after turning the power back on
@@ -821,7 +897,7 @@
 /*
  * Test IRadio.updateSimPhonebookRecords() for the response returned.
  */
-TEST_F(RadioHidlTest_v1_6, updateSimPhonebookRecords) {
+TEST_P(RadioHidlTest_v1_6, updateSimPhonebookRecords) {
     serial = GetRandomSerialNumber();
     radio_v1_6->getSimPhonebookCapacity(serial);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
@@ -851,7 +927,11 @@
         EXPECT_EQ(std::cv_status::no_timeout, wait());
         EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
         EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
-        EXPECT_EQ(::android::hardware::radio::V1_6::RadioError::NONE, radioRsp_v1_6->rspInfo.error);
+        ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_v1_6->rspInfo.error,
+            {::android::hardware::radio::V1_6::RadioError::NONE,
+             ::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED},
+             CHECK_GENERAL_ERROR));
 
         if(pbCapacity.maxAdnRecords > 0
                 && pbCapacity.usedAdnRecords < pbCapacity.maxAdnRecords) {
diff --git a/radio/1.6/vts/functional/radio_response.cpp b/radio/1.6/vts/functional/radio_response.cpp
index b1e679b..e1b9f56 100644
--- a/radio/1.6/vts/functional/radio_response.cpp
+++ b/radio/1.6/vts/functional/radio_response.cpp
@@ -1172,10 +1172,13 @@
 }
 
 Return<void> RadioResponse_v1_6::getAllowedNetworkTypesBitmapResponse(
-        const ::android::hardware::radio::V1_6::RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
         const ::android::hardware::hidl_bitfield<
                 ::android::hardware::radio::V1_4::RadioAccessFamily>
-        /*networkTypeBitmap*/) {
+                networkTypeBitmap) {
+    rspInfo = info;
+    networkTypeBitmapResponse = networkTypeBitmap;
+    parent_v1_6.notify(info.serial);
     return Void();
 }
 
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 9cc795d..88b2a26 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -233,8 +233,6 @@
      * indistinguishable from random.  Thus, if the entropy from any source is good, the output
      * must be good.
      *
-     * TODO(seleneh) specify what mixing functions and cprng we allow.
-     *
      * @param data Bytes to be mixed into the CRNG seed.  The caller must not provide more than 2
      *        KiB of data per invocation.
      *
@@ -805,9 +803,10 @@
     byte[] convertStorageKeyToEphemeral(in byte[] storageKeyBlob);
 
     /**
-     * Returns parameters associated with the provided key. This should match the
-     * KeyCharacteristics present in the KeyCreationResult returned by generateKey(),
-     * importKey(), or importWrappedKey().
+     * Returns KeyMint-enforced parameters associated with the provided key. The returned tags are
+     * a subset of KeyCharacteristics found in the KeyCreationResult returned by generateKey(),
+     * importKey(), or importWrappedKey(). The returned value is a subset, as it does not include
+     * any Keystore-enforced parameters.
      *
      * @param keyBlob The opaque descriptor returned by generateKey, importKey or importWrappedKey.
      *
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyCharacteristics.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyCharacteristics.aidl
index 25fdee3..f0df048 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyCharacteristics.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyCharacteristics.aidl
@@ -32,6 +32,17 @@
  */
 @VintfStability
 parcelable KeyCharacteristics {
+    /**
+     * The security level enforcing this collection of key properties.
+     */
     SecurityLevel securityLevel = SecurityLevel.SOFTWARE;
+
+    /**
+     * `authorizations` is a list of key properties that are enforced at this security level.
+     * A key can have different properties enforced by components of different security levels.
+     * For example, some properties are provided by the operating system, which has a
+     * different security level to the IKeyMintDevice.
+     * See the `keyCharacteristics` field in `KeyCreationResult` for more details.
+     */
     KeyParameter[] authorizations;
 }
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
index f93dbba..fd6bf65 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
@@ -159,18 +159,17 @@
      *     purpose                    [1] EXPLICIT SET OF INTEGER OPTIONAL,
      *     algorithm                  [2] EXPLICIT INTEGER OPTIONAL,
      *     keySize                    [3] EXPLICIT INTEGER OPTIONAL,
-     *     blockMode                  [4] EXPLICIT SET OF INTEGER OPTIONAL,
      *     digest                     [5] EXPLICIT SET OF INTEGER OPTIONAL,
      *     padding                    [6] EXPLICIT SET OF INTEGER OPTIONAL,
-     *     callerNonce                [7] EXPLICIT NULL OPTIONAL,
-     *     minMacLength               [8] EXPLICIT INTEGER OPTIONAL,
      *     ecCurve                    [10] EXPLICIT INTEGER OPTIONAL,
      *     rsaPublicExponent          [200] EXPLICIT INTEGER OPTIONAL,
+     *     mgfDigest                  [203] EXPLICIT SET OF INTEGER OPTIONAL,
      *     rollbackResistance         [303] EXPLICIT NULL OPTIONAL,
+     *     earlyBootOnly              [305] EXPLICIT NULL OPTIONAL,
      *     activeDateTime             [400] EXPLICIT INTEGER OPTIONAL,
      *     originationExpireDateTime  [401] EXPLICIT INTEGER OPTIONAL,
      *     usageExpireDateTime        [402] EXPLICIT INTEGER OPTIONAL,
-     *     userSecureId               [502] EXPLICIT INTEGER OPTIONAL,
+     *     usageCountLimit            [405] EXPLICIT INTEGER OPTIONAL,
      *     noAuthRequired             [503] EXPLICIT NULL OPTIONAL,
      *     userAuthType               [504] EXPLICIT INTEGER OPTIONAL,
      *     authTimeout                [505] EXPLICIT INTEGER OPTIONAL,
@@ -194,6 +193,7 @@
      *     attestationIdModel         [717] EXPLICIT OCTET_STRING OPTIONAL,
      *     vendorPatchLevel           [718] EXPLICIT INTEGER OPTIONAL,
      *     bootPatchLevel             [719] EXPLICIT INTEGER OPTIONAL,
+     *     deviceUniqueAttestation    [720] EXPLICIT NULL OPTIONAL,
      * }
      */
     Certificate[] certificateChain;
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyMintHardwareInfo.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyMintHardwareInfo.aidl
index 8da7578..b82dee6 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyMintHardwareInfo.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyMintHardwareInfo.aidl
@@ -29,7 +29,6 @@
      * Implementation version of the keymint hardware.  The version number is implementation
      * defined, and not necessarily globally meaningful.  The version is used to distinguish
      * between different versions of a given implementation.
-     * TODO(seleneh) add the version related info to the code.
      */
     int versionNumber;
 
diff --git a/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl b/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
index fbb373b..e71a9c9 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/PaddingMode.aidl
@@ -17,8 +17,6 @@
 package android.hardware.security.keymint;
 
 /**
- * TODO(seleneh) update the description.
- *
  * Padding modes that may be applied to plaintext for encryption operations.  This list includes
  * padding modes for both symmetric and asymmetric algorithms.  Note that implementations should not
  * provide all possible combinations of algorithm and padding, only the
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index 4ff4574..972ce2e 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -18,10 +18,6 @@
 
 import android.hardware.security.keymint.TagType;
 
-// TODO(seleneh) : note aidl currently does not support double nested enum definitions such as
-// ROOT_OF_TRUST = TagType:BYTES | 704.  So we are forced to write definitions as
-// ROOT_OF_TRUST = (9 << 28) for now.  Will need to flip this back later when aidl support is added.
-
 /**
  * Tag specifies various kinds of tags that can be set in KeyParameter to identify what kind of
  * data are stored in KeyParameter.
@@ -33,7 +29,7 @@
     /**
      * Tag::INVALID should never be set.  It means you hit an error.
      */
-    INVALID = (0 << 28) | 0,
+    INVALID = 0,
 
     /**
      * Tag::PURPOSE specifies the set of purposes for which the key may be used.  Possible values
@@ -47,7 +43,7 @@
      *
      * Must be hardware-enforced.
      */
-    PURPOSE = (2 << 28) /* TagType:ENUM_REP */ | 1,
+    PURPOSE = TagType.ENUM_REP | 1,
 
     /**
      * Tag::ALGORITHM specifies the cryptographic algorithm with which the key is used.  This tag
@@ -56,7 +52,7 @@
      *
      * Must be hardware-enforced.
      */
-    ALGORITHM = (1 << 28) /* TagType:ENUM */ | 2,
+    ALGORITHM = TagType.ENUM | 2,
 
     /**
      * Tag::KEY_SIZE specifies the size, in bits, of the key, measuring in the normal way for the
@@ -68,7 +64,7 @@
      *
      * Must be hardware-enforced.
      */
-    KEY_SIZE = (3 << 28) /* TagType:UINT */ | 3,
+    KEY_SIZE = TagType.UINT | 3,
 
     /**
      * Tag::BLOCK_MODE specifies the block cipher mode(s) with which the key may be used.  This tag
@@ -81,7 +77,7 @@
      *
      * Must be hardware-enforced.
      */
-    BLOCK_MODE = (2 << 28) /* TagType:ENUM_REP */ | 4,
+    BLOCK_MODE = TagType.ENUM_REP | 4,
 
     /**
      * Tag::DIGEST specifies the digest algorithms that may be used with the key to perform signing
@@ -95,7 +91,7 @@
      *
      * Must be hardware-enforced.
      */
-    DIGEST = (2 << 28) /* TagType:ENUM_REP */ | 5,
+    DIGEST = TagType.ENUM_REP | 5,
 
     /**
      * Tag::PADDING specifies the padding modes that may be used with the key.  This tag is relevant
@@ -123,7 +119,7 @@
      *
      * Must be hardware-enforced.
      */
-    PADDING = (2 << 28) /* TagType:ENUM_REP */ | 6,
+    PADDING = TagType.ENUM_REP | 6,
 
     /**
      * Tag::CALLER_NONCE specifies that the caller can provide a nonce for nonce-requiring
@@ -136,7 +132,7 @@
      *
      * Must be hardware-enforced.
      */
-    CALLER_NONCE = (7 << 28) /* TagType:BOOL */ | 7,
+    CALLER_NONCE = TagType.BOOL | 7,
 
     /**
      * Tag::MIN_MAC_LENGTH specifies the minimum length of MAC that can be requested or verified
@@ -149,7 +145,7 @@
      *
      * Must be hardware-enforced.
      */
-    MIN_MAC_LENGTH = (3 << 28) /* TagType:UINT */ | 8,
+    MIN_MAC_LENGTH = TagType.UINT | 8,
 
     // Tag 9 reserved
 
@@ -159,7 +155,7 @@
      *
      * Must be hardware-enforced.
      */
-    EC_CURVE = (1 << 28) /* TagType:ENUM */ | 10,
+    EC_CURVE = TagType.ENUM | 10,
 
     /**
      * Tag::RSA_PUBLIC_EXPONENT specifies the value of the public exponent for an RSA key pair.
@@ -173,7 +169,7 @@
      *
      * Must be hardware-enforced.
      */
-    RSA_PUBLIC_EXPONENT = (5 << 28) /* TagType:ULONG */ | 200,
+    RSA_PUBLIC_EXPONENT = TagType.ULONG | 200,
 
     // Tag 201 reserved
 
@@ -184,7 +180,7 @@
      *
      * Must be hardware-enforced.
      */
-    INCLUDE_UNIQUE_ID = (7 << 28) /* TagType:BOOL */ | 202,
+    INCLUDE_UNIQUE_ID = TagType.BOOL | 202,
 
     /**
      * Tag::RSA_OAEP_MGF_DIGEST specifies the MGF1 digest algorithms that may be used with RSA
@@ -197,7 +193,7 @@
      *
      * Must be hardware-enforced.
      */
-    RSA_OAEP_MGF_DIGEST = (2 << 28) /* TagType:ENUM_REP */ | 203,
+    RSA_OAEP_MGF_DIGEST = TagType.ENUM_REP | 203,
 
     // Tag 301 reserved
 
@@ -209,7 +205,7 @@
      *
      * Must be hardware-enforced.
      */
-    BOOTLOADER_ONLY = (7 << 28) /* TagType:BOOL */ | 302,
+    BOOTLOADER_ONLY = TagType.BOOL | 302,
 
     /**
      * Tag::ROLLBACK_RESISTANCE specifies that the key has rollback resistance, meaning that when
@@ -224,10 +220,10 @@
      *
      * Must be hardware-enforced.
      */
-    ROLLBACK_RESISTANCE = (7 << 28) /* TagType:BOOL */ | 303,
+    ROLLBACK_RESISTANCE = TagType.BOOL | 303,
 
     // Reserved for future use.
-    HARDWARE_TYPE = (1 << 28) /* TagType:ENUM */ | 304,
+    HARDWARE_TYPE = TagType.ENUM | 304,
 
     /**
      * Keys tagged with EARLY_BOOT_ONLY may only be used during early boot, until
@@ -236,7 +232,7 @@
      * provided to IKeyMintDevice::importKey, the import must fail with
      * ErrorCode::EARLY_BOOT_ENDED.
      */
-    EARLY_BOOT_ONLY = (7 << 28) /* TagType:BOOL */ | 305,
+    EARLY_BOOT_ONLY = TagType.BOOL | 305,
 
     /**
      * Tag::ACTIVE_DATETIME specifies the date and time at which the key becomes active, in
@@ -245,7 +241,7 @@
      *
      * Need not be hardware-enforced.
      */
-    ACTIVE_DATETIME = (6 << 28) /* TagType:DATE */ | 400,
+    ACTIVE_DATETIME = TagType.DATE | 400,
 
     /**
      * Tag::ORIGINATION_EXPIRE_DATETIME specifies the date and time at which the key expires for
@@ -257,7 +253,7 @@
      *
      * Need not be hardware-enforced.
      */
-    ORIGINATION_EXPIRE_DATETIME = (6 << 28) /* TagType:DATE */ | 401,
+    ORIGINATION_EXPIRE_DATETIME = TagType.DATE | 401,
 
     /**
      * Tag::USAGE_EXPIRE_DATETIME specifies the date and time at which the key expires for
@@ -269,13 +265,9 @@
      *
      * Need not be hardware-enforced.
      */
-    USAGE_EXPIRE_DATETIME = (6 << 28) /* TagType:DATE */ | 402,
+    USAGE_EXPIRE_DATETIME = TagType.DATE | 402,
 
     /**
-     * TODO(seleneh) this tag need to be deleted.
-     *
-     * TODO(seleneh) this tag need to be deleted.
-     *
      * Tag::MIN_SECONDS_BETWEEN_OPS specifies the minimum amount of time that elapses between
      * allowed operations using a key.  This can be used to rate-limit uses of keys in contexts
      * where unlimited use may enable brute force attacks.
@@ -293,8 +285,10 @@
      * fails because the table is full, KeyMint returns ErrorCode::TOO_MANY_OPERATIONS.
      *
      * Must be hardware-enforced.
+     *
+     * TODO(b/191458710): find out if this tag is still supported.
      */
-    MIN_SECONDS_BETWEEN_OPS = (3 << 28) /* TagType:UINT */ | 403,
+    MIN_SECONDS_BETWEEN_OPS = TagType.UINT | 403,
 
     /**
      * Tag::MAX_USES_PER_BOOT specifies the maximum number of times that a key may be used between
@@ -314,7 +308,7 @@
      *
      * Must be hardware-enforced.
      */
-    MAX_USES_PER_BOOT = (3 << 28) /* TagType:UINT */ | 404,
+    MAX_USES_PER_BOOT = TagType.UINT | 404,
 
     /**
      * Tag::USAGE_COUNT_LIMIT specifies the number of times that a key may be used. This can be
@@ -343,14 +337,14 @@
      * record. This tag must have the same SecurityLevel as the tag that is added to the key
      * characteristics.
      */
-    USAGE_COUNT_LIMIT = (3 << 28) | 405, /* TagType:UINT */
+    USAGE_COUNT_LIMIT = TagType.UINT | 405,
 
     /**
      * Tag::USER_ID specifies the ID of the Android user that is permitted to use the key.
      *
      * Must not be hardware-enforced.
      */
-    USER_ID = (3 << 28) /* TagType:UINT */ | 501,
+    USER_ID = TagType.UINT | 501,
 
     /**
      * Tag::USER_SECURE_ID specifies that a key may only be used under a particular secure user
@@ -383,7 +377,7 @@
      *
      * Must be hardware-enforced.
      */
-    USER_SECURE_ID = (10 << 28) /* TagType:ULONG_REP */ | 502,
+    USER_SECURE_ID = TagType.ULONG_REP | 502,
 
     /**
      * Tag::NO_AUTH_REQUIRED specifies that no authentication is required to use this key.  This tag
@@ -391,7 +385,7 @@
      *
      * Must be hardware-enforced.
      */
-    NO_AUTH_REQUIRED = (7 << 28) /* TagType:BOOL */ | 503,
+    NO_AUTH_REQUIRED = TagType.BOOL | 503,
 
     /**
      * Tag::USER_AUTH_TYPE specifies the types of user authenticators that may be used to authorize
@@ -410,7 +404,7 @@
      *
      * Must be hardware-enforced.
      */
-    USER_AUTH_TYPE = (1 << 28) /* TagType:ENUM */ | 504,
+    USER_AUTH_TYPE = TagType.ENUM | 504,
 
     /**
      * Tag::AUTH_TIMEOUT specifies the time in seconds for which the key is authorized for use,
@@ -424,7 +418,7 @@
      *
      * Must be hardware-enforced.
      */
-    AUTH_TIMEOUT = (3 << 28) /* TagType:UINT */ | 505,
+    AUTH_TIMEOUT = TagType.UINT | 505,
 
     /**
      * Tag::ALLOW_WHILE_ON_BODY specifies that the key may be used after authentication timeout if
@@ -432,7 +426,7 @@
      *
      * Cannot be hardware-enforced.
      */
-    ALLOW_WHILE_ON_BODY = (7 << 28) /* TagType:BOOL */ | 506,
+    ALLOW_WHILE_ON_BODY = TagType.BOOL | 506,
 
     /**
      * TRUSTED_USER_PRESENCE_REQUIRED is an optional feature that specifies that this key must be
@@ -479,7 +473,7 @@
      *
      * Must be hardware-enforced.
      */
-    TRUSTED_USER_PRESENCE_REQUIRED = (7 << 28) /* TagType:BOOL */ | 507,
+    TRUSTED_USER_PRESENCE_REQUIRED = TagType.BOOL | 507,
 
     /**
      * Tag::TRUSTED_CONFIRMATION_REQUIRED is only applicable to keys with KeyPurpose SIGN, and
@@ -493,7 +487,7 @@
      *
      * Must be hardware-enforced.
      */
-    TRUSTED_CONFIRMATION_REQUIRED = (7 << 28) /* TagType:BOOL */ | 508,
+    TRUSTED_CONFIRMATION_REQUIRED = TagType.BOOL | 508,
 
     /**
      * Tag::UNLOCKED_DEVICE_REQUIRED specifies that the key may only be used when the device is
@@ -501,7 +495,7 @@
      *
      * Must be software-enforced.
      */
-    UNLOCKED_DEVICE_REQUIRED = (7 << 28) /* TagType:BOOL */ | 509,
+    UNLOCKED_DEVICE_REQUIRED = TagType.BOOL | 509,
 
     /**
      * Tag::APPLICATION_ID.  When provided to generateKey or importKey, this tag specifies data
@@ -517,7 +511,7 @@
      *
      * Must never appear in KeyCharacteristics.
      */
-    APPLICATION_ID = (9 << 28) /* TagType:BYTES */ | 601,
+    APPLICATION_ID = TagType.BYTES | 601,
 
     /*
      * Semantically unenforceable tags, either because they have no specific meaning or because
@@ -538,7 +532,7 @@
      *
      * Must never appear in KeyCharacteristics.
      */
-    APPLICATION_DATA = (9 << 28) /* TagType:BYTES */ | 700,
+    APPLICATION_DATA = TagType.BYTES | 700,
 
     /**
      * Tag::CREATION_DATETIME specifies the date and time the key was created, in milliseconds since
@@ -546,7 +540,7 @@
      *
      * Must be in the software-enforced list, if provided.
      */
-    CREATION_DATETIME = (6 << 28) /* TagType:DATE */ | 701,
+    CREATION_DATETIME = TagType.DATE | 701,
 
     /**
      * Tag::ORIGIN specifies where the key was created, if known.  This tag must not be specified
@@ -555,7 +549,7 @@
      *
      * Must be hardware-enforced.
      */
-    ORIGIN = (1 << 28) /* TagType:ENUM */ | 702,
+    ORIGIN = TagType.ENUM | 702,
 
     // 703 is unused.
 
@@ -567,7 +561,7 @@
      *
      * Must never appear in KeyCharacteristics.
      */
-    ROOT_OF_TRUST = (9 << 28) /* TagType:BYTES */ | 704,
+    ROOT_OF_TRUST = TagType.BYTES | 704,
 
     /**
      * Tag::OS_VERSION specifies the system OS version with which the key may be used.  This tag is
@@ -590,7 +584,7 @@
      *
      * Must be hardware-enforced.
      */
-    OS_VERSION = (3 << 28) /* TagType:UINT */ | 705,
+    OS_VERSION = TagType.UINT | 705,
 
     /**
      * Tag::OS_PATCHLEVEL specifies the system security patch level with which the key may be used.
@@ -611,7 +605,7 @@
      *
      * Must be hardware-enforced.
      */
-    OS_PATCHLEVEL = (3 << 28) /* TagType:UINT */ | 706,
+    OS_PATCHLEVEL = TagType.UINT | 706,
 
     /**
      * Tag::UNIQUE_ID specifies a unique, time-based identifier.  This tag is never provided to or
@@ -646,7 +640,7 @@
      *
      * Must be hardware-enforced.
      */
-    UNIQUE_ID = (9 << 28) /* TagType:BYTES */ | 707,
+    UNIQUE_ID = TagType.BYTES | 707,
 
     /**
      * Tag::ATTESTATION_CHALLENGE is used to deliver a "challenge" value to the attested key
@@ -655,7 +649,7 @@
      *
      * Must never appear in KeyCharacteristics.
      */
-    ATTESTATION_CHALLENGE = (9 << 28) /* TagType:BYTES */ | 708,
+    ATTESTATION_CHALLENGE = TagType.BYTES | 708,
 
     /**
      * Tag::ATTESTATION_APPLICATION_ID identifies the set of applications which may use a key, used
@@ -681,7 +675,7 @@
      *
      * Cannot be hardware-enforced.
      */
-    ATTESTATION_APPLICATION_ID = (9 << 28) /* TagType:BYTES */ | 709,
+    ATTESTATION_APPLICATION_ID = TagType.BYTES | 709,
 
     /**
      * Tag::ATTESTATION_ID_BRAND provides the device's brand name, as returned by Build.BRAND in
@@ -694,7 +688,7 @@
      *
      * Must never appear in KeyCharacteristics.
      */
-    ATTESTATION_ID_BRAND = (9 << 28) /* TagType:BYTES */ | 710,
+    ATTESTATION_ID_BRAND = TagType.BYTES | 710,
 
     /**
      * Tag::ATTESTATION_ID_DEVICE provides the device's device name, as returned by Build.DEVICE in
@@ -707,7 +701,7 @@
      *
      * Must never appear in KeyCharacteristics.
      */
-    ATTESTATION_ID_DEVICE = (9 << 28) /* TagType:BYTES */ | 711,
+    ATTESTATION_ID_DEVICE = TagType.BYTES | 711,
 
     /**
      * Tag::ATTESTATION_ID_PRODUCT provides the device's product name, as returned by Build.PRODUCT
@@ -720,7 +714,7 @@
      *
      * Must never appear in KeyCharacteristics.
      */
-    ATTESTATION_ID_PRODUCT = (9 << 28) /* TagType:BYTES */ | 712,
+    ATTESTATION_ID_PRODUCT = TagType.BYTES | 712,
 
     /**
      * Tag::ATTESTATION_ID_SERIAL the device's serial number.  This field must be set only when
@@ -732,7 +726,7 @@
      *
      * Must never appear in KeyCharacteristics.
      */
-    ATTESTATION_ID_SERIAL = (9 << 28) /* TagType:BYTES */ | 713,
+    ATTESTATION_ID_SERIAL = TagType.BYTES | 713,
 
     /**
      * Tag::ATTESTATION_ID_IMEI provides the IMEIs for all radios on the device to attested key
@@ -745,7 +739,7 @@
      *
      * Must never appear in KeyCharacteristics.
      */
-    ATTESTATION_ID_IMEI = (9 << 28) /* TagType:BYTES */ | 714,
+    ATTESTATION_ID_IMEI = TagType.BYTES | 714,
 
     /**
      * Tag::ATTESTATION_ID_MEID provides the MEIDs for all radios on the device to attested key
@@ -758,7 +752,7 @@
      *
      * Must never appear in KeyCharacteristics.
      */
-    ATTESTATION_ID_MEID = (9 << 28) /* TagType:BYTES */ | 715,
+    ATTESTATION_ID_MEID = TagType.BYTES | 715,
 
     /**
      * Tag::ATTESTATION_ID_MANUFACTURER provides the device's manufacturer name, as returned by
@@ -771,7 +765,7 @@
      *
      * Must never appear in KeyCharacteristics.
      */
-    ATTESTATION_ID_MANUFACTURER = (9 << 28) /* TagType:BYTES */ | 716,
+    ATTESTATION_ID_MANUFACTURER = TagType.BYTES | 716,
 
     /**
      * Tag::ATTESTATION_ID_MODEL provides the device's model name, as returned by Build.MODEL in
@@ -784,7 +778,7 @@
      *
      * Must never appear in KeyCharacteristics.
      */
-    ATTESTATION_ID_MODEL = (9 << 28) /* TagType:BYTES */ | 717,
+    ATTESTATION_ID_MODEL = TagType.BYTES | 717,
 
     /**
      * Tag::VENDOR_PATCHLEVEL specifies the vendor image security patch level with which the key may
@@ -806,7 +800,7 @@
      *
      * Must be hardware-enforced.
      */
-    VENDOR_PATCHLEVEL = (3 << 28) /* TagType:UINT */ | 718,
+    VENDOR_PATCHLEVEL = TagType.UINT | 718,
 
     /**
      * Tag::BOOT_PATCHLEVEL specifies the boot image (kernel) security patch level with which the
@@ -826,23 +820,33 @@
      *
      * Must be hardware-enforced.
      */
-    BOOT_PATCHLEVEL = (3 << 28) /* TagType:UINT */ | 719,
+    BOOT_PATCHLEVEL = TagType.UINT | 719,
 
     /**
      * DEVICE_UNIQUE_ATTESTATION is an argument to IKeyMintDevice::attested key generation/import
      * operations.  It indicates that attestation using a device-unique key is requested, rather
-     * than a batch key.  When a device-unique key is used, only the attestation certificate is
-     * returned; no additional chained certificates are provided.  It's up to the caller to
-     * recognize the device-unique signing key.  Only SecurityLevel::STRONGBOX IKeyMintDevices may
-     * support device-unique attestations.  SecurityLevel::TRUSTED_ENVIRONMENT IKeyMintDevices must
-     * return ErrorCode::INVALID_ARGUMENT if they receive DEVICE_UNIQUE_ATTESTATION.
+     * than a batch key.  When a device-unique key is used, the returned chain should contain two
+     * certificates:
+     *    * The attestation certificate, containing the attestation extension, as described in
+            KeyCreationResult.aidl.
+     *    * A self-signed root certificate, signed by the device-unique key.
+     * No additional chained certificates are provided. Only SecurityLevel::STRONGBOX
+     * IKeyMintDevices may support device-unique attestations.  SecurityLevel::TRUSTED_ENVIRONMENT
+     * IKeyMintDevices must return ErrorCode::INVALID_ARGUMENT if they receive
+     * DEVICE_UNIQUE_ATTESTATION.
      * SecurityLevel::STRONGBOX IKeyMintDevices need not support DEVICE_UNIQUE_ATTESTATION, and
      * return ErrorCode::CANNOT_ATTEST_IDS if they do not support it.
      *
+     * The caller needs to obtain the device-unique keys out-of-band and compare them against the
+     * key used to sign the self-signed root certificate.
+     * To ease this process, the IKeyMintDevice implementation should include, both in the subject
+     * and issuer fields of the self-signed root, the unique identifier of the device. Using the
+     * unique identifier will make it straightforward for the caller to link a device to its key.
+     *
      * IKeyMintDevice implementations that support device-unique attestation MUST add the
      * DEVICE_UNIQUE_ATTESTATION tag to device-unique attestations.
      */
-    DEVICE_UNIQUE_ATTESTATION = (7 << 28) /* TagType:BOOL */ | 720,
+    DEVICE_UNIQUE_ATTESTATION = TagType.BOOL | 720,
 
     /**
      * IDENTITY_CREDENTIAL_KEY is never used by IKeyMintDevice, is not a valid argument to key
@@ -850,7 +854,7 @@
      * attestation.  It is used in attestations produced by the IIdentityCredential HAL when that
      * HAL attests to Credential Keys.  IIdentityCredential produces KeyMint-style attestations.
      */
-    IDENTITY_CREDENTIAL_KEY = (7 << 28) /* TagType:BOOL */ | 721,
+    IDENTITY_CREDENTIAL_KEY = TagType.BOOL | 721,
 
     /**
      * To prevent keys from being compromised if an attacker acquires read access to system / kernel
@@ -867,12 +871,13 @@
      * ErrorCode::INVALID_OPERATION is returned when a key with Tag::STORAGE_KEY is provided to
      * begin().
      */
-    STORAGE_KEY = (7 << 28) /* TagType:BOOL */ | 722,
+    STORAGE_KEY = TagType.BOOL | 722,
 
     /**
+     * OBSOLETE: Do not use. See IKeyMintOperation.updateAad instead.
      * TODO: Delete when keystore1 is deleted.
      */
-    ASSOCIATED_DATA = (9 << 28) /* TagType:BYTES */ | 1000,
+    ASSOCIATED_DATA = TagType.BYTES | 1000,
 
     /**
      * Tag::NONCE is used to provide or return a nonce or Initialization Vector (IV) for AES-GCM,
@@ -887,7 +892,7 @@
      *
      * Must never appear in KeyCharacteristics.
      */
-    NONCE = (9 << 28) /* TagType:BYTES */ | 1001,
+    NONCE = TagType.BYTES | 1001,
 
     /**
      * Tag::MAC_LENGTH provides the requested length of a MAC or GCM authentication tag, in bits.
@@ -898,7 +903,7 @@
      *
      * Must never appear in KeyCharacteristics.
      */
-    MAC_LENGTH = (3 << 28) /* TagType:UINT */ | 1003,
+    MAC_LENGTH = TagType.UINT | 1003,
 
     /**
      * Tag::RESET_SINCE_ID_ROTATION specifies whether the device has been factory reset since the
@@ -906,7 +911,7 @@
      *
      * Must never appear in KeyCharacteristics.
      */
-    RESET_SINCE_ID_ROTATION = (7 << 28) /* TagType:BOOL */ | 1004,
+    RESET_SINCE_ID_ROTATION = TagType.BOOL | 1004,
 
     /**
      * Tag::CONFIRMATION_TOKEN is used to deliver a cryptographic token proving that the user
@@ -915,7 +920,7 @@
      *
      * Must never appear in KeyCharacteristics.
      */
-    CONFIRMATION_TOKEN = (9 << 28) /* TagType:BYTES */ | 1005,
+    CONFIRMATION_TOKEN = TagType.BYTES | 1005,
 
     /**
      * Tag::CERTIFICATE_SERIAL specifies the serial number to be assigned to the attestation
@@ -923,7 +928,7 @@
      * keyMint in the attestation parameters during generateKey() and importKey().  If not provided,
      * the serial shall default to 1.
      */
-    CERTIFICATE_SERIAL = (8 << 28) /* TagType:BIGNUM */ | 1006,
+    CERTIFICATE_SERIAL = TagType.BIGNUM | 1006,
 
     /**
      * Tag::CERTIFICATE_SUBJECT the certificate subject.  The value is a DER encoded X509 NAME.
@@ -931,7 +936,7 @@
      * during generateKey and importKey. If not provided the subject name shall default to
      * CN="Android Keystore Key".
      */
-    CERTIFICATE_SUBJECT = (9 << 28) /* TagType:BYTES */ | 1007,
+    CERTIFICATE_SUBJECT = TagType.BYTES | 1007,
 
     /**
      * Tag::CERTIFICATE_NOT_BEFORE the beginning of the validity of the certificate in UNIX epoch
@@ -939,7 +944,7 @@
      * certificates.  ErrorCode::MISSING_NOT_BEFORE must be returned if this tag is not provided if
      * this tag is not provided to generateKey or importKey.
      */
-    CERTIFICATE_NOT_BEFORE = (6 << 28) /* TagType:DATE */ | 1008,
+    CERTIFICATE_NOT_BEFORE = TagType.DATE | 1008,
 
     /**
      * Tag::CERTIFICATE_NOT_AFTER the end of the validity of the certificate in UNIX epoch time in
@@ -947,7 +952,7 @@
      * ErrorCode::MISSING_NOT_AFTER must be returned if this tag is not provided to generateKey or
      * importKey.
      */
-    CERTIFICATE_NOT_AFTER = (6 << 28) /* TagType:DATE */ | 1009,
+    CERTIFICATE_NOT_AFTER = TagType.DATE | 1009,
 
     /**
      * Tag::MAX_BOOT_LEVEL specifies a maximum boot level at which a key should function.
@@ -958,5 +963,5 @@
      *
      * Cannot be hardware enforced in this version.
      */
-    MAX_BOOT_LEVEL = (3 << 28) /* TagType:UINT */ | 1010,
+    MAX_BOOT_LEVEL = TagType.UINT | 1010,
 }
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index b8699e9..a312723 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -141,11 +141,18 @@
                               attest_key, &attested_key_blob, &attested_key_characteristics,
                               &attested_key_cert_chain));
 
+        // The returned key characteristics will include CREATION_DATETIME (checked below)
+        // in SecurityLevel::KEYSTORE; this will be stripped out in the CheckCharacteristics()
+        // call below, to match what getKeyCharacteristics() returns (which doesn't include
+        // any SecurityLevel::KEYSTORE characteristics).
+        CheckCharacteristics(attested_key_blob, attested_key_characteristics);
+
         CheckedDeleteKey(&attested_key_blob);
         CheckedDeleteKey(&attest_key.keyBlob);
 
         hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
         sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+
         // The client-specified CREATION_DATETIME should be in sw_enforced.
         // Its presence will also trigger verify_attestation_record() to check that it
         // is in the attestation extension with a matching value.
@@ -549,7 +556,7 @@
                                                      .EcdsaSigningKey(curve)
                                                      .AttestKey()
                                                      .SetDefaultValidity(),
-                                             {} /* attestation siging key */, &attest_key.keyBlob,
+                                             {} /* attestation signing key */, &attest_key.keyBlob,
                                              &attest_key_characteristics, &attest_key_cert_chain));
 
         ASSERT_GT(attest_key_cert_chain.size(), 0);
@@ -633,7 +640,7 @@
             ErrorCode::OK,
             GenerateKey(
                     AuthorizationSetBuilder().EcdsaSigningKey(EcCurve::P_256).SetDefaultValidity(),
-                    {} /* attestation siging key */, &non_attest_key.keyBlob,
+                    {} /* attestation signing key */, &non_attest_key.keyBlob,
                     &non_attest_key_characteristics, &non_attest_key_cert_chain));
 
     ASSERT_GT(non_attest_key_cert_chain.size(), 0);
@@ -655,6 +662,124 @@
                           &attested_key_cert_chain));
 }
 
+TEST_P(AttestKeyTest, EcdsaAttestationID) {
+    // Create attestation key.
+    AttestationKey attest_key;
+    vector<KeyCharacteristics> attest_key_characteristics;
+    vector<Certificate> attest_key_cert_chain;
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .EcdsaSigningKey(EcCurve::P_256)
+                                                 .AttestKey()
+                                                 .SetDefaultValidity(),
+                                         {} /* attestation signing key */, &attest_key.keyBlob,
+                                         &attest_key_characteristics, &attest_key_cert_chain));
+    attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+    ASSERT_GT(attest_key_cert_chain.size(), 0);
+    EXPECT_EQ(attest_key_cert_chain.size(), 1);
+    EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain));
+
+    // Collection of valid attestation ID tags.
+    auto attestation_id_tags = AuthorizationSetBuilder();
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
+                      "ro.product.manufacturer");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
+
+    for (const KeyParameter& tag : attestation_id_tags) {
+        SCOPED_TRACE(testing::Message() << "+tag-" << tag);
+        // Use attestation key to sign an ECDSA key, but include an attestation ID field.
+        AuthorizationSetBuilder builder = AuthorizationSetBuilder()
+                                                  .EcdsaSigningKey(EcCurve::P_256)
+                                                  .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                  .AttestationChallenge("challenge")
+                                                  .AttestationApplicationId("foo")
+                                                  .SetDefaultValidity();
+        builder.push_back(tag);
+        vector<uint8_t> attested_key_blob;
+        vector<KeyCharacteristics> attested_key_characteristics;
+        vector<Certificate> attested_key_cert_chain;
+        auto result = GenerateKey(builder, attest_key, &attested_key_blob,
+                                  &attested_key_characteristics, &attested_key_cert_chain);
+        if (result == ErrorCode::CANNOT_ATTEST_IDS) {
+            continue;
+        }
+
+        ASSERT_EQ(result, ErrorCode::OK);
+
+        CheckedDeleteKey(&attested_key_blob);
+
+        AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+        AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+
+        // The attested key characteristics will not contain APPLICATION_ID_* fields (their
+        // spec definitions all have "Must never appear in KeyCharacteristics"), but the
+        // attestation extension should contain them, so make sure the extra tag is added.
+        hw_enforced.push_back(tag);
+
+        EXPECT_TRUE(verify_attestation_record("challenge", "foo", sw_enforced, hw_enforced,
+                                              SecLevel(),
+                                              attested_key_cert_chain[0].encodedCertificate));
+    }
+    CheckedDeleteKey(&attest_key.keyBlob);
+}
+
+TEST_P(AttestKeyTest, EcdsaAttestationMismatchID) {
+    // Create attestation key.
+    AttestationKey attest_key;
+    vector<KeyCharacteristics> attest_key_characteristics;
+    vector<Certificate> attest_key_cert_chain;
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .EcdsaSigningKey(EcCurve::P_256)
+                                                 .AttestKey()
+                                                 .SetDefaultValidity(),
+                                         {} /* attestation signing key */, &attest_key.keyBlob,
+                                         &attest_key_characteristics, &attest_key_cert_chain));
+    attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+    ASSERT_GT(attest_key_cert_chain.size(), 0);
+    EXPECT_EQ(attest_key_cert_chain.size(), 1);
+    EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain));
+
+    // Collection of invalid attestation ID tags.
+    auto attestation_id_tags =
+            AuthorizationSetBuilder()
+                    .Authorization(TAG_ATTESTATION_ID_BRAND, "bogus-brand")
+                    .Authorization(TAG_ATTESTATION_ID_DEVICE, "devious-device")
+                    .Authorization(TAG_ATTESTATION_ID_PRODUCT, "punctured-product")
+                    .Authorization(TAG_ATTESTATION_ID_SERIAL, "suspicious-serial")
+                    .Authorization(TAG_ATTESTATION_ID_IMEI, "invalid-imei")
+                    .Authorization(TAG_ATTESTATION_ID_MEID, "mismatching-meid")
+                    .Authorization(TAG_ATTESTATION_ID_MANUFACTURER, "malformed-manufacturer")
+                    .Authorization(TAG_ATTESTATION_ID_MODEL, "malicious-model");
+    vector<uint8_t> key_blob;
+    vector<KeyCharacteristics> key_characteristics;
+
+    for (const KeyParameter& invalid_tag : attestation_id_tags) {
+        SCOPED_TRACE(testing::Message() << "+tag-" << invalid_tag);
+
+        // Use attestation key to sign an ECDSA key, but include an invalid
+        // attestation ID field.
+        AuthorizationSetBuilder builder = AuthorizationSetBuilder()
+                                                  .EcdsaSigningKey(EcCurve::P_256)
+                                                  .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                  .AttestationChallenge("challenge")
+                                                  .AttestationApplicationId("foo")
+                                                  .SetDefaultValidity();
+        builder.push_back(invalid_tag);
+        vector<uint8_t> attested_key_blob;
+        vector<KeyCharacteristics> attested_key_characteristics;
+        vector<Certificate> attested_key_cert_chain;
+        auto result = GenerateKey(builder, attest_key, &attested_key_blob,
+                                  &attested_key_characteristics, &attested_key_cert_chain);
+
+        ASSERT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG)
+                << "result = " << result;
+    }
+    CheckedDeleteKey(&attest_key.keyBlob);
+}
+
 INSTANTIATE_KEYMINT_AIDL_TEST(AttestKeyTest);
 
 }  // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
index b0f056a..a3ed3ad 100644
--- a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
+++ b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -29,7 +29,7 @@
   protected:
     void CheckUniqueAttestationResults(const vector<uint8_t>& key_blob,
                                        const vector<KeyCharacteristics>& key_characteristics,
-                                       const AuthorizationSet& hw_enforced, int key_size) {
+                                       const AuthorizationSet& hw_enforced) {
         ASSERT_GT(cert_chain_.size(), 0);
 
         if (KeyMintAidlTestBase::dump_Attestations) {
@@ -40,10 +40,11 @@
 
         AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
 
-        EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size)) << "Key size missing";
-
+        // The device-unique attestation chain should contain exactly two certificates:
+        // * The leaf with the attestation extension.
+        // * A self-signed root, signed using the device-unique key.
+        ASSERT_EQ(cert_chain_.size(), 2);
         EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
-        ASSERT_GT(cert_chain_.size(), 0);
 
         AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
         EXPECT_TRUE(verify_attestation_record("challenge", "foo", sw_enforced, hw_enforced,
@@ -133,17 +134,32 @@
 
     ASSERT_EQ(ErrorCode::OK, result);
 
-    AuthorizationSet 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());
+    AuthorizationSetBuilder 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());
 
-    CheckUniqueAttestationResults(key_blob, key_characteristics, hw_enforced, key_size);
+    // Any patchlevels attached to the key should also be present in the attestation extension.
+    AuthorizationSet auths;
+    for (const auto& entry : key_characteristics) {
+        auths.push_back(AuthorizationSet(entry.authorizations));
+    }
+    auto vendor_pl = auths.GetTagValue(TAG_VENDOR_PATCHLEVEL);
+    if (vendor_pl) {
+        hw_enforced.Authorization(TAG_VENDOR_PATCHLEVEL, *vendor_pl);
+    }
+    auto boot_pl = auths.GetTagValue(TAG_BOOT_PATCHLEVEL);
+    if (boot_pl) {
+        hw_enforced.Authorization(TAG_BOOT_PATCHLEVEL, *boot_pl);
+    }
+
+    CheckUniqueAttestationResults(key_blob, key_characteristics, hw_enforced);
 }
 
 /*
@@ -157,11 +173,10 @@
 
     vector<uint8_t> key_blob;
     vector<KeyCharacteristics> key_characteristics;
-    int key_size = 256;
 
     auto result = GenerateKey(AuthorizationSetBuilder()
                                       .Authorization(TAG_NO_AUTH_REQUIRED)
-                                      .EcdsaSigningKey(256)
+                                      .EcdsaSigningKey(EcCurve::P_256)
                                       .Digest(Digest::SHA_2_256)
                                       .Authorization(TAG_INCLUDE_UNIQUE_ID)
                                       .AttestationChallenge("challenge")
@@ -173,17 +188,137 @@
     if (result == ErrorCode::CANNOT_ATTEST_IDS) return;
     ASSERT_EQ(ErrorCode::OK, result);
 
-    AuthorizationSet hw_enforced = AuthorizationSetBuilder()
-                                           .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
-                                           .Authorization(TAG_NO_AUTH_REQUIRED)
-                                           .EcdsaSigningKey(EcCurve::P_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());
+    AuthorizationSetBuilder hw_enforced =
+            AuthorizationSetBuilder()
+                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                    .EcdsaSigningKey(EcCurve::P_256)
+                    .Digest(Digest::SHA_2_256)
+                    .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+                    .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
+                    .Authorization(TAG_OS_VERSION, os_version())
+                    .Authorization(TAG_OS_PATCHLEVEL, os_patch_level());
+    // Any patchlevels attached to the key should also be present in the attestation extension.
+    AuthorizationSet auths;
+    for (const auto& entry : key_characteristics) {
+        auths.push_back(AuthorizationSet(entry.authorizations));
+    }
+    auto vendor_pl = auths.GetTagValue(TAG_VENDOR_PATCHLEVEL);
+    if (vendor_pl) {
+        hw_enforced.Authorization(TAG_VENDOR_PATCHLEVEL, *vendor_pl);
+    }
+    auto boot_pl = auths.GetTagValue(TAG_BOOT_PATCHLEVEL);
+    if (boot_pl) {
+        hw_enforced.Authorization(TAG_BOOT_PATCHLEVEL, *boot_pl);
+    }
 
-    CheckUniqueAttestationResults(key_blob, key_characteristics, hw_enforced, key_size);
+    CheckUniqueAttestationResults(key_blob, key_characteristics, hw_enforced);
+}
+
+/*
+ * DeviceUniqueAttestationTest.EcdsaDeviceUniqueAttestationID
+ *
+ * Verifies that device unique attestation can include IDs that do match the
+ * local device.
+ */
+TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestationID) {
+    if (SecLevel() != SecurityLevel::STRONGBOX) return;
+
+    // Collection of valid attestation ID tags.
+    auto attestation_id_tags = AuthorizationSetBuilder();
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
+                      "ro.product.manufacturer");
+    add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
+    vector<uint8_t> key_blob;
+    vector<KeyCharacteristics> key_characteristics;
+
+    for (const KeyParameter& tag : attestation_id_tags) {
+        SCOPED_TRACE(testing::Message() << "+tag-" << tag);
+        AuthorizationSetBuilder builder = AuthorizationSetBuilder()
+                                                  .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                  .EcdsaSigningKey(EcCurve::P_256)
+                                                  .Digest(Digest::SHA_2_256)
+                                                  .Authorization(TAG_INCLUDE_UNIQUE_ID)
+                                                  .AttestationChallenge("challenge")
+                                                  .AttestationApplicationId("foo")
+                                                  .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION);
+        builder.push_back(tag);
+        auto result = GenerateKey(builder, &key_blob, &key_characteristics);
+
+        // It is optional for Strong box to support DeviceUniqueAttestation.
+        if (result == ErrorCode::CANNOT_ATTEST_IDS) return;
+        ASSERT_EQ(ErrorCode::OK, result);
+
+        AuthorizationSetBuilder hw_enforced =
+                AuthorizationSetBuilder()
+                        .Authorization(TAG_NO_AUTH_REQUIRED)
+                        .EcdsaSigningKey(EcCurve::P_256)
+                        .Digest(Digest::SHA_2_256)
+                        .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION)
+                        .Authorization(TAG_ORIGIN, KeyOrigin::GENERATED)
+                        .Authorization(TAG_OS_VERSION, os_version())
+                        .Authorization(TAG_OS_PATCHLEVEL, os_patch_level());
+        // Expect the specified tag to be present in the attestation extension.
+        hw_enforced.push_back(tag);
+        // Any patchlevels attached to the key should also be present in the attestation extension.
+        AuthorizationSet auths;
+        for (const auto& entry : key_characteristics) {
+            auths.push_back(AuthorizationSet(entry.authorizations));
+        }
+        auto vendor_pl = auths.GetTagValue(TAG_VENDOR_PATCHLEVEL);
+        if (vendor_pl) {
+            hw_enforced.Authorization(TAG_VENDOR_PATCHLEVEL, *vendor_pl);
+        }
+        auto boot_pl = auths.GetTagValue(TAG_BOOT_PATCHLEVEL);
+        if (boot_pl) {
+            hw_enforced.Authorization(TAG_BOOT_PATCHLEVEL, *boot_pl);
+        }
+        CheckUniqueAttestationResults(key_blob, key_characteristics, hw_enforced);
+    }
+}
+
+/*
+ * DeviceUniqueAttestationTest.EcdsaDeviceUniqueAttestationMismatchID
+ *
+ * Verifies that device unique attestation rejects attempts to attest to IDs that
+ * don't match the local device.
+ */
+TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestationMismatchID) {
+    if (SecLevel() != SecurityLevel::STRONGBOX) return;
+
+    // Collection of invalid attestation ID tags.
+    auto attestation_id_tags =
+            AuthorizationSetBuilder()
+                    .Authorization(TAG_ATTESTATION_ID_BRAND, "bogus-brand")
+                    .Authorization(TAG_ATTESTATION_ID_DEVICE, "devious-device")
+                    .Authorization(TAG_ATTESTATION_ID_PRODUCT, "punctured-product")
+                    .Authorization(TAG_ATTESTATION_ID_SERIAL, "suspicious-serial")
+                    .Authorization(TAG_ATTESTATION_ID_IMEI, "invalid-imei")
+                    .Authorization(TAG_ATTESTATION_ID_MEID, "mismatching-meid")
+                    .Authorization(TAG_ATTESTATION_ID_MANUFACTURER, "malformed-manufacturer")
+                    .Authorization(TAG_ATTESTATION_ID_MODEL, "malicious-model");
+    vector<uint8_t> key_blob;
+    vector<KeyCharacteristics> key_characteristics;
+
+    for (const KeyParameter& invalid_tag : attestation_id_tags) {
+        SCOPED_TRACE(testing::Message() << "+tag-" << invalid_tag);
+        AuthorizationSetBuilder builder = AuthorizationSetBuilder()
+                                                  .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                  .EcdsaSigningKey(EcCurve::P_256)
+                                                  .Digest(Digest::SHA_2_256)
+                                                  .Authorization(TAG_INCLUDE_UNIQUE_ID)
+                                                  .AttestationChallenge("challenge")
+                                                  .AttestationApplicationId("foo")
+                                                  .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION);
+        // Add the tag that doesn't match the local device's real ID.
+        builder.push_back(invalid_tag);
+        auto result = GenerateKey(builder, &key_blob, &key_characteristics);
+
+        ASSERT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG);
+    }
 }
 
 INSTANTIATE_KEYMINT_AIDL_TEST(DeviceUniqueAttestationTest);
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index a9a67bc..44b8274 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -142,6 +142,15 @@
     return filtered;
 }
 
+// Remove any SecurityLevel::KEYSTORE entries from a list of key characteristics.
+void strip_keystore_tags(vector<KeyCharacteristics>* characteristics) {
+    characteristics->erase(std::remove_if(characteristics->begin(), characteristics->end(),
+                                          [](const auto& entry) {
+                                              return entry.securityLevel == SecurityLevel::KEYSTORE;
+                                          }),
+                           characteristics->end());
+}
+
 string x509NameToStr(X509_NAME* name) {
     char* s = X509_NAME_oneline(name, nullptr, 0);
     string retval(s);
@@ -320,6 +329,65 @@
     return GetReturnErrorCode(result);
 }
 
+ErrorCode KeyMintAidlTestBase::GetCharacteristics(const vector<uint8_t>& key_blob,
+                                                  const vector<uint8_t>& app_id,
+                                                  const vector<uint8_t>& app_data,
+                                                  vector<KeyCharacteristics>* key_characteristics) {
+    Status result =
+            keymint_->getKeyCharacteristics(key_blob, app_id, app_data, key_characteristics);
+    return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::GetCharacteristics(const vector<uint8_t>& key_blob,
+                                                  vector<KeyCharacteristics>* key_characteristics) {
+    vector<uint8_t> empty_app_id, empty_app_data;
+    return GetCharacteristics(key_blob, empty_app_id, empty_app_data, key_characteristics);
+}
+
+void KeyMintAidlTestBase::CheckCharacteristics(
+        const vector<uint8_t>& key_blob,
+        const vector<KeyCharacteristics>& generate_characteristics) {
+    // Any key characteristics that were in SecurityLevel::KEYSTORE when returned from
+    // generateKey() should be excluded, as KeyMint will have no record of them.
+    // This applies to CREATION_DATETIME in particular.
+    vector<KeyCharacteristics> expected_characteristics(generate_characteristics);
+    strip_keystore_tags(&expected_characteristics);
+
+    vector<KeyCharacteristics> retrieved;
+    ASSERT_EQ(ErrorCode::OK, GetCharacteristics(key_blob, &retrieved));
+    EXPECT_EQ(expected_characteristics, retrieved);
+}
+
+void KeyMintAidlTestBase::CheckAppIdCharacteristics(
+        const vector<uint8_t>& key_blob, std::string_view app_id_string,
+        std::string_view app_data_string,
+        const vector<KeyCharacteristics>& generate_characteristics) {
+    // Exclude any SecurityLevel::KEYSTORE characteristics for comparisons.
+    vector<KeyCharacteristics> expected_characteristics(generate_characteristics);
+    strip_keystore_tags(&expected_characteristics);
+
+    vector<uint8_t> app_id(app_id_string.begin(), app_id_string.end());
+    vector<uint8_t> app_data(app_data_string.begin(), app_data_string.end());
+    vector<KeyCharacteristics> retrieved;
+    ASSERT_EQ(ErrorCode::OK, GetCharacteristics(key_blob, app_id, app_data, &retrieved));
+    EXPECT_EQ(expected_characteristics, retrieved);
+
+    // Check that key characteristics can't be retrieved if the app ID or app data is missing.
+    vector<uint8_t> empty;
+    vector<KeyCharacteristics> not_retrieved;
+    EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+              GetCharacteristics(key_blob, empty, app_data, &not_retrieved));
+    EXPECT_EQ(not_retrieved.size(), 0);
+
+    EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+              GetCharacteristics(key_blob, app_id, empty, &not_retrieved));
+    EXPECT_EQ(not_retrieved.size(), 0);
+
+    EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+              GetCharacteristics(key_blob, empty, empty, &not_retrieved));
+    EXPECT_EQ(not_retrieved.size(), 0);
+}
+
 ErrorCode KeyMintAidlTestBase::DeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob) {
     Status result = keymint_->deleteKey(*key_blob);
     if (!keep_key_blob) {
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index d8f1bb3..82f192a 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -16,8 +16,12 @@
 
 #pragma once
 
+#include <functional>
+#include <string_view>
+
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
+#include <android-base/properties.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <gtest/gtest.h>
@@ -104,6 +108,18 @@
                                 unwrapping_params, 0 /* password_sid */, 0 /* biometric_sid */);
     }
 
+    ErrorCode GetCharacteristics(const vector<uint8_t>& key_blob, const vector<uint8_t>& app_id,
+                                 const vector<uint8_t>& app_data,
+                                 vector<KeyCharacteristics>* key_characteristics);
+    ErrorCode GetCharacteristics(const vector<uint8_t>& key_blob,
+                                 vector<KeyCharacteristics>* key_characteristics);
+
+    void CheckCharacteristics(const vector<uint8_t>& key_blob,
+                              const vector<KeyCharacteristics>& generate_characteristics);
+    void CheckAppIdCharacteristics(const vector<uint8_t>& key_blob, std::string_view app_id_string,
+                                   std::string_view app_data_string,
+                                   const vector<KeyCharacteristics>& generate_characteristics);
+
     ErrorCode DeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob = false);
     ErrorCode DeleteKey(bool keep_key_blob = false);
 
@@ -192,50 +208,58 @@
     template <typename TagType>
     std::tuple<KeyData /* aesKey */, KeyData /* hmacKey */, KeyData /* rsaKey */,
                KeyData /* ecdsaKey */>
-    CreateTestKeys(TagType tagToTest, ErrorCode expectedReturn) {
+    CreateTestKeys(
+            TagType tagToTest, ErrorCode expectedReturn,
+            std::function<void(AuthorizationSetBuilder*)> tagModifier =
+                    [](AuthorizationSetBuilder*) {}) {
         /* AES */
         KeyData aesKeyData;
-        ErrorCode errorCode = GenerateKey(AuthorizationSetBuilder()
-                                                  .AesEncryptionKey(128)
-                                                  .Authorization(tagToTest)
-                                                  .BlockMode(BlockMode::ECB)
-                                                  .Padding(PaddingMode::NONE)
-                                                  .Authorization(TAG_NO_AUTH_REQUIRED),
-                                          &aesKeyData.blob, &aesKeyData.characteristics);
+        AuthorizationSetBuilder aesBuilder = AuthorizationSetBuilder()
+                                                     .AesEncryptionKey(128)
+                                                     .Authorization(tagToTest)
+                                                     .BlockMode(BlockMode::ECB)
+                                                     .Padding(PaddingMode::NONE)
+                                                     .Authorization(TAG_NO_AUTH_REQUIRED);
+        tagModifier(&aesBuilder);
+        ErrorCode errorCode =
+                GenerateKey(aesBuilder, &aesKeyData.blob, &aesKeyData.characteristics);
         EXPECT_EQ(expectedReturn, errorCode);
 
         /* HMAC */
         KeyData hmacKeyData;
-        errorCode = GenerateKey(AuthorizationSetBuilder()
-                                        .HmacKey(128)
-                                        .Authorization(tagToTest)
-                                        .Digest(Digest::SHA_2_256)
-                                        .Authorization(TAG_MIN_MAC_LENGTH, 128)
-                                        .Authorization(TAG_NO_AUTH_REQUIRED),
-                                &hmacKeyData.blob, &hmacKeyData.characteristics);
+        AuthorizationSetBuilder hmacBuilder = AuthorizationSetBuilder()
+                                                      .HmacKey(128)
+                                                      .Authorization(tagToTest)
+                                                      .Digest(Digest::SHA_2_256)
+                                                      .Authorization(TAG_MIN_MAC_LENGTH, 128)
+                                                      .Authorization(TAG_NO_AUTH_REQUIRED);
+        tagModifier(&hmacBuilder);
+        errorCode = GenerateKey(hmacBuilder, &hmacKeyData.blob, &hmacKeyData.characteristics);
         EXPECT_EQ(expectedReturn, errorCode);
 
         /* RSA */
         KeyData rsaKeyData;
-        errorCode = GenerateKey(AuthorizationSetBuilder()
-                                        .RsaSigningKey(2048, 65537)
-                                        .Authorization(tagToTest)
-                                        .Digest(Digest::NONE)
-                                        .Padding(PaddingMode::NONE)
-                                        .Authorization(TAG_NO_AUTH_REQUIRED)
-                                        .SetDefaultValidity(),
-                                &rsaKeyData.blob, &rsaKeyData.characteristics);
+        AuthorizationSetBuilder rsaBuilder = AuthorizationSetBuilder()
+                                                     .RsaSigningKey(2048, 65537)
+                                                     .Authorization(tagToTest)
+                                                     .Digest(Digest::NONE)
+                                                     .Padding(PaddingMode::NONE)
+                                                     .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                     .SetDefaultValidity();
+        tagModifier(&rsaBuilder);
+        errorCode = GenerateKey(rsaBuilder, &rsaKeyData.blob, &rsaKeyData.characteristics);
         EXPECT_EQ(expectedReturn, errorCode);
 
         /* ECDSA */
         KeyData ecdsaKeyData;
-        errorCode = GenerateKey(AuthorizationSetBuilder()
-                                        .EcdsaSigningKey(256)
-                                        .Authorization(tagToTest)
-                                        .Digest(Digest::SHA_2_256)
-                                        .Authorization(TAG_NO_AUTH_REQUIRED)
-                                        .SetDefaultValidity(),
-                                &ecdsaKeyData.blob, &ecdsaKeyData.characteristics);
+        AuthorizationSetBuilder ecdsaBuilder = AuthorizationSetBuilder()
+                                                       .EcdsaSigningKey(256)
+                                                       .Authorization(tagToTest)
+                                                       .Digest(Digest::SHA_2_256)
+                                                       .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                       .SetDefaultValidity();
+        tagModifier(&ecdsaBuilder);
+        errorCode = GenerateKey(ecdsaBuilder, &ecdsaKeyData.blob, &ecdsaKeyData.characteristics);
         EXPECT_EQ(expectedReturn, errorCode);
         return {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData};
     }
@@ -290,6 +314,16 @@
     long challenge_;
 };
 
+// If the given property is available, add it to the tag set under the given tag ID.
+template <Tag tag>
+void add_tag_from_prop(AuthorizationSetBuilder* tags, TypedTag<TagType::BYTES, tag> ttag,
+                       const char* prop) {
+    std::string prop_value = ::android::base::GetProperty(prop, /* default= */ "");
+    if (!prop_value.empty()) {
+        tags->Authorization(ttag, prop_value.data(), prop_value.size());
+    }
+}
+
 vector<uint8_t> build_serial_blob(const uint64_t serial_int);
 void verify_subject(const X509* cert, const string& subject, bool self_signed);
 void verify_serial(X509* cert, const uint64_t expected_serial);
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 8b1eb30..295be1a 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -560,6 +560,7 @@
 
                 EXPECT_GT(key_blob.size(), 0U);
                 CheckSymmetricParams(key_characteristics);
+                CheckCharacteristics(key_blob, key_characteristics);
 
                 AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
 
@@ -742,6 +743,7 @@
 
                 EXPECT_GT(key_blob.size(), 0U);
                 CheckSymmetricParams(key_characteristics);
+                CheckCharacteristics(key_blob, key_characteristics);
 
                 AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
 
@@ -788,6 +790,7 @@
 
                 EXPECT_GT(key_blob.size(), 0U);
                 CheckSymmetricParams(key_characteristics);
+                CheckCharacteristics(key_blob, key_characteristics);
 
                 AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
 
@@ -865,6 +868,7 @@
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
 
         AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
 
@@ -911,6 +915,7 @@
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
 
         AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
 
@@ -978,6 +983,7 @@
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
 
         AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
 
@@ -1108,6 +1114,7 @@
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
 
         AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
 
@@ -1176,6 +1183,7 @@
 
     ASSERT_GT(key_blob.size(), 0U);
     CheckBaseParams(key_characteristics);
+    CheckCharacteristics(key_blob, key_characteristics);
 
     AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
 
@@ -1211,6 +1219,7 @@
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
 
         AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
 
@@ -1266,6 +1275,7 @@
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
 
         AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
 
@@ -1362,6 +1372,7 @@
                                              &key_blob, &key_characteristics));
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
 
         AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
 
@@ -1405,6 +1416,7 @@
                               &key_blob, &key_characteristics));
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
 
         AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
 
@@ -1452,6 +1464,7 @@
                               &key_blob, &key_characteristics));
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
 
         AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
 
@@ -1511,6 +1524,7 @@
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
 
         AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
 
@@ -1555,6 +1569,7 @@
                                              &key_blob, &key_characteristics));
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
 
         AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
 
@@ -1594,6 +1609,7 @@
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
 
         AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
 
@@ -1726,6 +1742,7 @@
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
 
         AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
         EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::HMAC));
@@ -1761,6 +1778,7 @@
         ASSERT_GT(key_blob.size(), 0U);
         ASSERT_EQ(cert_chain_.size(), 0);
         CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
 
         AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
         EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::HMAC));
@@ -1791,6 +1809,7 @@
 
         ASSERT_GT(key_blob.size(), 0U);
         CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
 
         AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
         EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::HMAC));
@@ -2044,6 +2063,9 @@
                                                  .Authorization(TAG_APPLICATION_ID, "clientid")
                                                  .Authorization(TAG_APPLICATION_DATA, "appdata")
                                                  .SetDefaultValidity()));
+
+    CheckAppIdCharacteristics(key_blob_, "clientid", "appdata", key_characteristics_);
+
     EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
               Begin(KeyPurpose::SIGN,
                     AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
@@ -2558,6 +2580,9 @@
                                                  .Authorization(TAG_APPLICATION_ID, "clientid")
                                                  .Authorization(TAG_APPLICATION_DATA, "appdata")
                                                  .SetDefaultValidity()));
+
+    CheckAppIdCharacteristics(key_blob_, "clientid", "appdata", key_characteristics_);
+
     EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
               Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Digest(Digest::NONE)));
     AbortIfNeeded();
@@ -6330,6 +6355,11 @@
     auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] =
             CreateTestKeys(TAG_EARLY_BOOT_ONLY, ErrorCode::OK);
 
+    for (const auto& keyData : {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData}) {
+        ASSERT_GT(keyData.blob.size(), 0U);
+        AuthorizationSet crypto_params = SecLevelAuthorizations(keyData.characteristics);
+        EXPECT_TRUE(crypto_params.Contains(TAG_EARLY_BOOT_ONLY)) << crypto_params;
+    }
     CheckedDeleteKey(&aesKeyData.blob);
     CheckedDeleteKey(&hmacKeyData.blob);
     CheckedDeleteKey(&rsaKeyData.blob);
@@ -6337,7 +6367,30 @@
 }
 
 /*
- * EarlyBootKeyTest.UsetEarlyBootKeyFailure
+ * EarlyBootKeyTest.CreateAttestedEarlyBootKey
+ *
+ * Verifies that creating an early boot key with attestation succeeds.
+ */
+TEST_P(EarlyBootKeyTest, CreateAttestedEarlyBootKey) {
+    auto [aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData] = CreateTestKeys(
+            TAG_EARLY_BOOT_ONLY, ErrorCode::OK, [](AuthorizationSetBuilder* builder) {
+                builder->AttestationChallenge("challenge");
+                builder->AttestationApplicationId("app_id");
+            });
+
+    for (const auto& keyData : {aesKeyData, hmacKeyData, rsaKeyData, ecdsaKeyData}) {
+        ASSERT_GT(keyData.blob.size(), 0U);
+        AuthorizationSet crypto_params = SecLevelAuthorizations(keyData.characteristics);
+        EXPECT_TRUE(crypto_params.Contains(TAG_EARLY_BOOT_ONLY)) << crypto_params;
+    }
+    CheckedDeleteKey(&aesKeyData.blob);
+    CheckedDeleteKey(&hmacKeyData.blob);
+    CheckedDeleteKey(&rsaKeyData.blob);
+    CheckedDeleteKey(&ecdsaKeyData.blob);
+}
+
+/*
+ * EarlyBootKeyTest.UseEarlyBootKeyFailure
  *
  * Verifies that using early boot keys at a later stage fails.
  */
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index a2071c2..a177317 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -340,6 +340,7 @@
                                               cppbor::Array()  // SignedMacAad
                                                       .add(challenge_)
                                                       .add(std::move(deviceInfoMap))
+                                                      .add(keysToSignMac)
                                                       .encode());
         ASSERT_TRUE(macKey) << macKey.message();
 
diff --git a/security/keymint/support/attestation_record.cpp b/security/keymint/support/attestation_record.cpp
index a48f770..2462228 100644
--- a/security/keymint/support/attestation_record.cpp
+++ b/security/keymint/support/attestation_record.cpp
@@ -64,6 +64,7 @@
 } ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
 IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
 
+// Fields ordered in tag order.
 typedef struct km_auth_list {
     ASN1_INTEGER_SET* purpose;
     ASN1_INTEGER* algorithm;
@@ -72,32 +73,38 @@
     ASN1_INTEGER_SET* padding;
     ASN1_INTEGER* ec_curve;
     ASN1_INTEGER* rsa_public_exponent;
+    ASN1_INTEGER_SET* mgf_digest;
+    ASN1_NULL* rollback_resistance;
+    ASN1_NULL* early_boot_only;
     ASN1_INTEGER* active_date_time;
     ASN1_INTEGER* origination_expire_date_time;
     ASN1_INTEGER* usage_expire_date_time;
+    ASN1_INTEGER* usage_count_limit;
     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_NULL* trusted_user_presence_required;
+    ASN1_NULL* trusted_confirmation_required;
+    ASN1_NULL* unlocked_device_required;
     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_OCTET_STRING* attestation_id_brand;
+    ASN1_OCTET_STRING* attestation_id_device;
+    ASN1_OCTET_STRING* attestation_id_product;
+    ASN1_OCTET_STRING* attestation_id_serial;
+    ASN1_OCTET_STRING* attestation_id_imei;
+    ASN1_OCTET_STRING* attestation_id_meid;
+    ASN1_OCTET_STRING* attestation_id_manufacturer;
+    ASN1_OCTET_STRING* attestation_id_model;
     ASN1_INTEGER* vendor_patchlevel;
     ASN1_INTEGER* boot_patchlevel;
-    ASN1_NULL* early_boot_only;
     ASN1_NULL* device_unique_attestation;
-    ASN1_NULL* storage_key;
     ASN1_NULL* identity_credential;
-    ASN1_INTEGER* usage_count_limit;
 } KM_AUTH_LIST;
 
 ASN1_SEQUENCE(KM_AUTH_LIST) = {
@@ -109,13 +116,18 @@
         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_SET_OF_OPT(KM_AUTH_LIST, mgf_digest, ASN1_INTEGER,
+                            TAG_RSA_OAEP_MGF_DIGEST.maskedTag()),
         ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL,
                      TAG_ROLLBACK_RESISTANCE.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.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, usage_count_limit, ASN1_INTEGER,
+                     TAG_USAGE_COUNT_LIMIT.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()),
@@ -133,19 +145,31 @@
         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, attestation_application_id, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_brand, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_BRAND.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_device, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_DEVICE.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_product, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_PRODUCT.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_serial, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_SERIAL.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_imei, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_IMEI.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_meid, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_MEID.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_manufacturer, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_MANUFACTURER.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_id_model, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_ID_MODEL.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_EXP_OPT(KM_AUTH_LIST, storage_key, ASN1_NULL, TAG_STORAGE_KEY.maskedTag()),
         ASN1_EXP_OPT(KM_AUTH_LIST, identity_credential, ASN1_NULL,
                      TAG_IDENTITY_CREDENTIAL_KEY.maskedTag()),
-        ASN1_EXP_OPT(KM_AUTH_LIST, usage_count_limit, ASN1_INTEGER,
-                     TAG_USAGE_COUNT_LIMIT.maskedTag()),
 } ASN1_SEQUENCE_END(KM_AUTH_LIST);
 IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
 
@@ -155,9 +179,9 @@
     ASN1_INTEGER* keymint_version;
     ASN1_ENUMERATED* keymint_security_level;
     ASN1_OCTET_STRING* attestation_challenge;
+    ASN1_INTEGER* unique_id;
     KM_AUTH_LIST* software_enforced;
     KM_AUTH_LIST* tee_enforced;
-    ASN1_INTEGER* unique_id;
 } KM_KEY_DESCRIPTION;
 
 ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = {
@@ -253,41 +277,52 @@
 }
 
 // Extract the values from the specified ASN.1 record and place them in auth_list.
+// Does nothing with root-of-trust field.
 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);
+    // Fields ordered in tag order.
     copyAuthTag(record->purpose, TAG_PURPOSE, auth_list);
-    copyAuthTag(record->rollback_resistance, TAG_ROLLBACK_RESISTANCE, auth_list);
+    copyAuthTag(record->algorithm, TAG_ALGORITHM, auth_list);
+    copyAuthTag(record->key_size, TAG_KEY_SIZE, auth_list);
+    copyAuthTag(record->digest, TAG_DIGEST, auth_list);
+    copyAuthTag(record->padding, TAG_PADDING, auth_list);
+    copyAuthTag(record->ec_curve, TAG_EC_CURVE, auth_list);
     copyAuthTag(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list);
+    copyAuthTag(record->mgf_digest, TAG_RSA_OAEP_MGF_DIGEST, auth_list);
+    copyAuthTag(record->rollback_resistance, TAG_ROLLBACK_RESISTANCE, auth_list);
+    copyAuthTag(record->early_boot_only, TAG_EARLY_BOOT_ONLY, auth_list);
+    copyAuthTag(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list);
+    copyAuthTag(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, auth_list);
     copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list);
+    copyAuthTag(record->usage_count_limit, TAG_USAGE_COUNT_LIMIT, auth_list);
+    copyAuthTag(record->no_auth_required, TAG_NO_AUTH_REQUIRED, 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->auth_timeout, TAG_AUTH_TIMEOUT, auth_list);
+    copyAuthTag(record->allow_while_on_body, TAG_ALLOW_WHILE_ON_BODY, 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->creation_date_time, TAG_CREATION_DATETIME, auth_list);
+    copyAuthTag(record->origin, TAG_ORIGIN, auth_list);
+    // root_of_trust dealt with separately
+    copyAuthTag(record->os_version, TAG_OS_VERSION, auth_list);
+    copyAuthTag(record->os_patchlevel, TAG_OS_PATCHLEVEL, auth_list);
+    copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list);
+    copyAuthTag(record->attestation_id_brand, TAG_ATTESTATION_ID_BRAND, auth_list);
+    copyAuthTag(record->attestation_id_device, TAG_ATTESTATION_ID_DEVICE, auth_list);
+    copyAuthTag(record->attestation_id_product, TAG_ATTESTATION_ID_PRODUCT, auth_list);
+    copyAuthTag(record->attestation_id_serial, TAG_ATTESTATION_ID_SERIAL, auth_list);
+    copyAuthTag(record->attestation_id_imei, TAG_ATTESTATION_ID_IMEI, auth_list);
+    copyAuthTag(record->attestation_id_meid, TAG_ATTESTATION_ID_MEID, auth_list);
+    copyAuthTag(record->attestation_id_manufacturer, TAG_ATTESTATION_ID_MANUFACTURER, auth_list);
+    copyAuthTag(record->attestation_id_model, TAG_ATTESTATION_ID_MODEL, auth_list);
+    copyAuthTag(record->vendor_patchlevel, TAG_VENDOR_PATCHLEVEL, auth_list);
+    copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list);
     copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list);
-    copyAuthTag(record->storage_key, TAG_STORAGE_KEY, auth_list);
     copyAuthTag(record->identity_credential, TAG_IDENTITY_CREDENTIAL_KEY, auth_list);
-    copyAuthTag(record->usage_count_limit, TAG_USAGE_COUNT_LIMIT, auth_list);
 
     return ErrorCode::OK;
 }
diff --git a/security/keymint/support/keymint_utils.cpp b/security/keymint/support/keymint_utils.cpp
index 2dbdfa8..1e0733f 100644
--- a/security/keymint/support/keymint_utils.cpp
+++ b/security/keymint/support/keymint_utils.cpp
@@ -32,10 +32,11 @@
 
 constexpr char kPlatformPatchlevelProp[] = "ro.build.version.security_patch";
 constexpr char kVendorPatchlevelProp[] = "ro.vendor.build.security_patch";
-constexpr char kPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-[0-9]{2}$";
+constexpr char kPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-([0-9]{2})$";
 constexpr size_t kYearMatch = 1;
 constexpr size_t kMonthMatch = 2;
-constexpr size_t kPatchlevelMatchCount = kMonthMatch + 1;
+constexpr size_t kDayMatch = 3;
+constexpr size_t kPatchlevelMatchCount = kDayMatch + 1;
 
 uint32_t match_to_uint32(const char* expression, const regmatch_t& match) {
     if (match.rm_so == -1) return 0;
@@ -53,8 +54,6 @@
     return prop_value;
 }
 
-}  // anonymous namespace
-
 uint32_t getOsVersion(const char* version_str) {
     regex_t regex;
     if (regcomp(&regex, kPlatformVersionRegex, REG_EXTENDED)) {
@@ -76,12 +75,9 @@
     return (major * 100 + minor) * 100 + subminor;
 }
 
-uint32_t getOsVersion() {
-    std::string version = wait_and_get_property(kPlatformVersionProp);
-    return getOsVersion(version.c_str());
-}
+enum class PatchlevelOutput { kYearMonthDay, kYearMonth };
 
-uint32_t getPatchlevel(const char* patchlevel_str) {
+uint32_t getPatchlevel(const char* patchlevel_str, PatchlevelOutput detail) {
     regex_t regex;
     if (regcomp(&regex, kPatchlevelRegex, REG_EXTENDED) != 0) {
         return 0;
@@ -100,17 +96,35 @@
     if (month < 1 || month > 12) {
         return 0;
     }
-    return year * 100 + month;
+
+    switch (detail) {
+        case PatchlevelOutput::kYearMonthDay: {
+            uint32_t day = match_to_uint32(patchlevel_str, matches[kDayMatch]);
+            if (day < 1 || day > 31) {
+                return 0;
+            }
+            return year * 10000 + month * 100 + day;
+        }
+        case PatchlevelOutput::kYearMonth:
+            return year * 100 + month;
+    }
+}
+
+}  // anonymous namespace
+
+uint32_t getOsVersion() {
+    std::string version = wait_and_get_property(kPlatformVersionProp);
+    return getOsVersion(version.c_str());
 }
 
 uint32_t getOsPatchlevel() {
     std::string patchlevel = wait_and_get_property(kPlatformPatchlevelProp);
-    return getPatchlevel(patchlevel.c_str());
+    return getPatchlevel(patchlevel.c_str(), PatchlevelOutput::kYearMonth);
 }
 
 uint32_t getVendorPatchlevel() {
     std::string patchlevel = wait_and_get_property(kVendorPatchlevelProp);
-    return getPatchlevel(patchlevel.c_str());
+    return getPatchlevel(patchlevel.c_str(), PatchlevelOutput::kYearMonthDay);
 }
 
 }  // namespace aidl::android::hardware::security::keymint
diff --git a/security/secureclock/aidl/android/hardware/security/secureclock/TimeStampToken.aidl b/security/secureclock/aidl/android/hardware/security/secureclock/TimeStampToken.aidl
index 2fbd29a..fcf2ee8 100644
--- a/security/secureclock/aidl/android/hardware/security/secureclock/TimeStampToken.aidl
+++ b/security/secureclock/aidl/android/hardware/security/secureclock/TimeStampToken.aidl
@@ -39,7 +39,7 @@
      * 32-byte HMAC-SHA256 of the above values, computed as:
      *
      *    HMAC(H,
-     *         ISecureClock.TIME_STAMP_MAC_LABEL || challenge || timestamp || securityLevel )
+     *         ISecureClock.TIME_STAMP_MAC_LABEL || challenge || timestamp || 1 )
      *
      * where:
      *
@@ -50,9 +50,7 @@
      *   ``||'' represents concatenation
      *
      * The representation of challenge and timestamp is as 64-bit unsigned integers in big-endian
-     * order. SecurityLevel is represented as a 32-bit unsigned integer in big-endian order as
-     * described in android.hardware.security.keymint.SecurityLevel. It represents the security
-     * level of the secure clock environment.
+     * order.  1, above, is a 32-bit unsigned integer, also big-endian.
      */
     byte[] mac;
 }
diff --git a/security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp b/security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp
index 31f4854..bf332d5 100644
--- a/security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp
+++ b/security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp
@@ -114,6 +114,7 @@
     EXPECT_EQ(ErrorCode::OK, result1.error);
     EXPECT_EQ(1U, result1.token.challenge);
     EXPECT_GT(result1.token.timestamp.milliSeconds, 0U);
+    EXPECT_EQ(32U, result1.token.mac.size());
 
     unsigned long time_to_sleep = 200;
     sleep_ms(time_to_sleep);
@@ -123,6 +124,7 @@
     EXPECT_EQ(ErrorCode::OK, result2.error);
     EXPECT_EQ(2U, result2.token.challenge);
     EXPECT_GT(result2.token.timestamp.milliSeconds, 0U);
+    EXPECT_EQ(32U, result2.token.mac.size());
 
     auto host_time_delta = result2_time - result1_time;
 
@@ -153,6 +155,7 @@
     EXPECT_EQ(ErrorCode::OK, result1.error);
     EXPECT_EQ(0U, result1.token.challenge);
     EXPECT_GT(result1.token.timestamp.milliSeconds, 0U);
+    EXPECT_EQ(32U, result1.token.mac.size());
 
     unsigned long time_to_sleep = 200;
     sleep_ms(time_to_sleep);
@@ -162,6 +165,7 @@
     EXPECT_EQ(ErrorCode::OK, result2.error);
     EXPECT_EQ(1U, result2.token.challenge);
     EXPECT_GT(result2.token.timestamp.milliSeconds, 0U);
+    EXPECT_EQ(32U, result2.token.mac.size());
 
     auto host_time_delta = result2_time - result1_time;
 
diff --git a/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp b/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
index 8426120..919f882 100644
--- a/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
+++ b/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
@@ -48,6 +48,9 @@
         SharedSecretParameters params;
         auto error = GetReturnErrorCode(sharedSecret->getSharedSecretParameters(&params));
         EXPECT_EQ(ErrorCode::OK, error);
+        EXPECT_TRUE(params.seed.size() == 0 || params.seed.size() == 32);
+        EXPECT_TRUE(params.nonce.size() == 32);
+
         GetParamsResult result;
         result.tie() = std::tie(error, params);
         return result;
@@ -234,6 +237,45 @@
     }
 }
 
+TEST_F(SharedSecretAidlTest, ComputeSharedSecretShortNonce) {
+    auto sharedSecrets = allSharedSecrets();
+    if (sharedSecrets.empty()) {
+        GTEST_SKIP() << "Skipping the test as no shared secret service is found.";
+    }
+    auto fixup_hmac = finally([&]() { computeAllSharedSecrets(getAllSharedSecretParameters()); });
+
+    auto params = getAllSharedSecretParameters();
+    ASSERT_EQ(sharedSecrets.size(), params.size())
+            << "One or more shared secret services failed to provide parameters.";
+
+    // All should be well in the normal case
+    auto responses = computeAllSharedSecrets(params);
+
+    ASSERT_GT(responses.size(), 0U);
+    vector<uint8_t> correct_response = responses[0].sharing_check;
+    verifyResponses(correct_response, responses);
+
+    // Pick a random param and shorten that nonce by one.
+    size_t param_to_tweak = rand() % params.size();
+    auto& to_tweak = params[param_to_tweak].nonce;
+    ASSERT_TRUE(to_tweak.size() == 32);
+    to_tweak.resize(31);
+
+    responses = computeAllSharedSecrets(params);
+    for (size_t i = 0; i < responses.size(); ++i) {
+        if (i == param_to_tweak) {
+            EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
+                    << "Shared secret service that provided tweaked param should fail to compute "
+                       "shared secret";
+        } else {
+            EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
+            EXPECT_NE(correct_response, responses[i].sharing_check)
+                    << "Others should calculate a different shared secret, due to the tweaked "
+                       "nonce.";
+        }
+    }
+}
+
 TEST_F(SharedSecretAidlTest, ComputeSharedSecretCorruptSeed) {
     auto sharedSecrets = allSharedSecrets();
     if (sharedSecrets.empty()) {
@@ -275,6 +317,45 @@
         }
     }
 }
+
+TEST_F(SharedSecretAidlTest, ComputeSharedSecretShortSeed) {
+    auto sharedSecrets = allSharedSecrets();
+    if (sharedSecrets.empty()) {
+        GTEST_SKIP() << "Skipping the test as no shared secret service is found.";
+    }
+    auto fixup_hmac = finally([&]() { computeAllSharedSecrets(getAllSharedSecretParameters()); });
+    auto params = getAllSharedSecretParameters();
+    ASSERT_EQ(sharedSecrets.size(), params.size())
+            << "One or more shared secret service failed to provide parameters.";
+
+    // All should be well in the normal case
+    auto responses = computeAllSharedSecrets(params);
+
+    ASSERT_GT(responses.size(), 0U);
+    vector<uint8_t> correct_response = responses[0].sharing_check;
+    verifyResponses(correct_response, responses);
+
+    // Pick a random param and modify the seed to be of (invalid) length 31.
+    auto param_to_tweak = rand() % params.size();
+    auto& to_tweak = params[param_to_tweak].seed;
+    ASSERT_TRUE(to_tweak.size() == 32 || to_tweak.size() == 0);
+    to_tweak.resize(31);
+
+    responses = computeAllSharedSecrets(params);
+    for (size_t i = 0; i < responses.size(); ++i) {
+        if (i == param_to_tweak) {
+            EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
+                    << "Shared secret service that provided tweaked param should fail to compute "
+                       "shared secret";
+        } else {
+            EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
+            EXPECT_NE(correct_response, responses[i].sharing_check)
+                    << "Others should calculate a different shared secret, due to the tweaked "
+                       "nonce.";
+        }
+    }
+}
+
 }  // namespace aidl::android::hardware::security::sharedsecret::test
 
 int main(int argc, char** argv) {