Merge "VTS: Reduce TV's advertising set requirement to 10" into udc-dev
diff --git a/audio/aidl/default/EffectConfig.cpp b/audio/aidl/default/EffectConfig.cpp
index 5a83fef..71d111b 100644
--- a/audio/aidl/default/EffectConfig.cpp
+++ b/audio/aidl/default/EffectConfig.cpp
@@ -14,12 +14,17 @@
  * limitations under the License.
  */
 
+#include <optional>
+#include <string>
 #define LOG_TAG "AHAL_EffectConfig"
 #include <android-base/logging.h>
+#include <system/audio_effects/audio_effects_conf.h>
 #include <system/audio_effects/effect_uuid.h>
 
 #include "effectFactory-impl/EffectConfig.h"
 
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::AudioStreamType;
 using aidl::android::media::audio::common::AudioUuid;
 
 namespace aidl::android::hardware::audio::effect {
@@ -55,14 +60,16 @@
         // Parse pre processing chains
         for (auto& xmlPreprocess : getChildren(xmlConfig, "preprocess")) {
             for (auto& xmlStream : getChildren(xmlPreprocess, "stream")) {
-                registerFailure(parseStream(xmlStream));
+                // AudioSource
+                registerFailure(parseProcessing(Processing::Type::source, xmlStream));
             }
         }
 
         // Parse post processing chains
         for (auto& xmlPostprocess : getChildren(xmlConfig, "postprocess")) {
             for (auto& xmlStream : getChildren(xmlPostprocess, "stream")) {
-                registerFailure(parseStream(xmlStream));
+                // AudioStreamType
+                registerFailure(parseProcessing(Processing::Type::streamType, xmlStream));
             }
         }
     }
@@ -140,21 +147,6 @@
     return true;
 }
 
-bool EffectConfig::parseStream(const tinyxml2::XMLElement& xml) {
-    LOG(DEBUG) << __func__ << dump(xml);
-    const char* type = xml.Attribute("type");
-    RETURN_VALUE_IF(!type, false, "noTypeInProcess");
-    RETURN_VALUE_IF(0 != mProcessingMap.count(type), false, "duplicateType");
-
-    for (auto& apply : getChildren(xml, "apply")) {
-        const char* name = apply.get().Attribute("effect");
-        RETURN_VALUE_IF(!name, false, "noEffectAttribute");
-        mProcessingMap[type].push_back(name);
-        LOG(DEBUG) << __func__ << " " << type << " : " << name;
-    }
-    return true;
-}
-
 bool EffectConfig::parseLibraryUuid(const tinyxml2::XMLElement& xml,
                                     struct LibraryUuid& libraryUuid, bool isProxy) {
     // Retrieve library name only if not effectProxy element
@@ -174,6 +166,80 @@
     return true;
 }
 
+std::optional<Processing::Type> EffectConfig::stringToProcessingType(Processing::Type::Tag typeTag,
+                                                                     const std::string& type) {
+    // see list of audio stream types in audio_stream_type_t:
+    // system/media/audio/include/system/audio_effects/audio_effects_conf.h
+    // AUDIO_STREAM_DEFAULT_TAG is not listed here because according to SYS_RESERVED_DEFAULT in
+    // AudioStreamType.aidl: "Value reserved for system use only. HALs must never return this value
+    // to the system or accept it from the system".
+    static const std::map<const std::string, AudioStreamType> sAudioStreamTypeTable = {
+            {AUDIO_STREAM_VOICE_CALL_TAG, AudioStreamType::VOICE_CALL},
+            {AUDIO_STREAM_SYSTEM_TAG, AudioStreamType::SYSTEM},
+            {AUDIO_STREAM_RING_TAG, AudioStreamType::RING},
+            {AUDIO_STREAM_MUSIC_TAG, AudioStreamType::MUSIC},
+            {AUDIO_STREAM_ALARM_TAG, AudioStreamType::ALARM},
+            {AUDIO_STREAM_NOTIFICATION_TAG, AudioStreamType::NOTIFICATION},
+            {AUDIO_STREAM_BLUETOOTH_SCO_TAG, AudioStreamType::BLUETOOTH_SCO},
+            {AUDIO_STREAM_ENFORCED_AUDIBLE_TAG, AudioStreamType::ENFORCED_AUDIBLE},
+            {AUDIO_STREAM_DTMF_TAG, AudioStreamType::DTMF},
+            {AUDIO_STREAM_TTS_TAG, AudioStreamType::TTS},
+            {AUDIO_STREAM_ASSISTANT_TAG, AudioStreamType::ASSISTANT}};
+
+    // see list of audio sources in audio_source_t:
+    // system/media/audio/include/system/audio_effects/audio_effects_conf.h
+    static const std::map<const std::string, AudioSource> sAudioSourceTable = {
+            {MIC_SRC_TAG, AudioSource::VOICE_CALL},
+            {VOICE_UL_SRC_TAG, AudioSource::VOICE_CALL},
+            {VOICE_DL_SRC_TAG, AudioSource::VOICE_CALL},
+            {VOICE_CALL_SRC_TAG, AudioSource::VOICE_CALL},
+            {CAMCORDER_SRC_TAG, AudioSource::VOICE_CALL},
+            {VOICE_REC_SRC_TAG, AudioSource::VOICE_CALL},
+            {VOICE_COMM_SRC_TAG, AudioSource::VOICE_CALL},
+            {REMOTE_SUBMIX_SRC_TAG, AudioSource::VOICE_CALL},
+            {UNPROCESSED_SRC_TAG, AudioSource::VOICE_CALL},
+            {VOICE_PERFORMANCE_SRC_TAG, AudioSource::VOICE_CALL}};
+
+    if (typeTag == Processing::Type::streamType) {
+        auto typeIter = sAudioStreamTypeTable.find(type);
+        if (typeIter != sAudioStreamTypeTable.end()) {
+            return typeIter->second;
+        }
+    } else if (typeTag == Processing::Type::source) {
+        auto typeIter = sAudioSourceTable.find(type);
+        if (typeIter != sAudioSourceTable.end()) {
+            return typeIter->second;
+        }
+    }
+
+    return std::nullopt;
+}
+
+bool EffectConfig::parseProcessing(Processing::Type::Tag typeTag, const tinyxml2::XMLElement& xml) {
+    LOG(DEBUG) << __func__ << dump(xml);
+    const char* typeStr = xml.Attribute("type");
+    auto aidlType = stringToProcessingType(typeTag, typeStr);
+    RETURN_VALUE_IF(!aidlType.has_value(), false, "illegalStreamType");
+    RETURN_VALUE_IF(0 != mProcessingMap.count(aidlType.value()), false, "duplicateStreamType");
+
+    for (auto& apply : getChildren(xml, "apply")) {
+        const char* name = apply.get().Attribute("effect");
+        if (mEffectsMap.find(name) == mEffectsMap.end()) {
+            LOG(ERROR) << __func__ << " effect " << name << " doesn't exist, skipping";
+            continue;
+        }
+        RETURN_VALUE_IF(!name, false, "noEffectAttribute");
+        mProcessingMap[aidlType.value()].emplace_back(mEffectsMap[name]);
+        LOG(WARNING) << __func__ << " " << typeStr << " : " << name;
+    }
+    return true;
+}
+
+const std::map<Processing::Type, std::vector<EffectConfig::EffectLibraries>>&
+EffectConfig::getProcessingMap() const {
+    return mProcessingMap;
+}
+
 bool EffectConfig::findUuid(const std::string& xmlEffectName, AudioUuid* uuid) {
 // Difference from EFFECT_TYPE_LIST_DEF, there could be multiple name mapping to same Effect Type
 #define EFFECT_XML_TYPE_LIST_DEF(V)                        \
diff --git a/audio/aidl/default/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp
index f0687cc..7073a10 100644
--- a/audio/aidl/default/EffectFactory.cpp
+++ b/audio/aidl/default/EffectFactory.cpp
@@ -15,8 +15,10 @@
  */
 
 #include <dlfcn.h>
+#include <algorithm>
 #include <iterator>
 #include <memory>
+#include <optional>
 #include <tuple>
 #include <unordered_set>
 #define LOG_TAG "AHAL_EffectFactory"
@@ -52,6 +54,22 @@
     }
 }
 
+ndk::ScopedAStatus Factory::getDescriptorWithUuid(const AudioUuid& uuid, Descriptor* desc) {
+    RETURN_IF(!desc, EX_NULL_POINTER, "nullDescriptor");
+
+    if (mEffectLibMap.count(uuid)) {
+        auto& entry = mEffectLibMap[uuid];
+        getDlSyms(entry);
+        auto& libInterface = std::get<kMapEntryInterfaceIndex>(entry);
+        RETURN_IF(!libInterface || !libInterface->queryEffectFunc, EX_NULL_POINTER,
+                  "dlNullQueryEffectFunc");
+        RETURN_IF_BINDER_EXCEPTION(libInterface->queryEffectFunc(&uuid, desc));
+        return ndk::ScopedAStatus::ok();
+    }
+
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
 ndk::ScopedAStatus Factory::queryEffects(const std::optional<AudioUuid>& in_type_uuid,
                                          const std::optional<AudioUuid>& in_impl_uuid,
                                          const std::optional<AudioUuid>& in_proxy_uuid,
@@ -69,12 +87,7 @@
     for (const auto& id : idList) {
         if (mEffectLibMap.count(id.uuid)) {
             Descriptor desc;
-            auto& entry = mEffectLibMap[id.uuid];
-            getDlSyms(entry);
-            auto& libInterface = std::get<kMapEntryInterfaceIndex>(entry);
-            RETURN_IF(!libInterface || !libInterface->queryEffectFunc, EX_NULL_POINTER,
-                      "dlNullQueryEffectFunc");
-            RETURN_IF_BINDER_EXCEPTION(libInterface->queryEffectFunc(&id.uuid, &desc));
+            RETURN_IF_ASTATUS_NOT_OK(getDescriptorWithUuid(id.uuid, &desc), "getDescriptorFailed");
             // update proxy UUID with information from config xml
             desc.common.id.proxy = id.proxy;
             _aidl_return->emplace_back(std::move(desc));
@@ -85,12 +98,26 @@
 
 ndk::ScopedAStatus Factory::queryProcessing(const std::optional<Processing::Type>& in_type,
                                             std::vector<Processing>* _aidl_return) {
-    // TODO: implement this with audio_effect.xml.
-    if (in_type.has_value()) {
-        // return all matching process filter
-        LOG(DEBUG) << __func__ << " process type: " << in_type.value().toString();
+    const auto& processings = mConfig.getProcessingMap();
+    // Processing stream type
+    for (const auto& procIter : processings) {
+        if (!in_type.has_value() || in_type.value() == procIter.first) {
+            Processing process = {.type = procIter.first /* Processing::Type */};
+            for (const auto& libs : procIter.second /* std::vector<struct EffectLibraries> */) {
+                for (const auto& lib : libs.libraries /* std::vector<struct LibraryUuid> */) {
+                    Descriptor desc;
+                    if (libs.proxyLibrary.has_value()) {
+                        desc.common.id.proxy = libs.proxyLibrary.value().uuid;
+                    }
+                    RETURN_IF_ASTATUS_NOT_OK(getDescriptorWithUuid(lib.uuid, &desc),
+                                             "getDescriptorFailed");
+                    process.ids.emplace_back(desc);
+                }
+            }
+            _aidl_return->emplace_back(process);
+        }
     }
-    LOG(DEBUG) << __func__ << " return " << _aidl_return->size();
+
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index c06742d..6627ae7 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -95,8 +95,17 @@
             <libsw library="bundle" uuid="ce772f20-847d-11df-bb17-0002a5d5c51b"/>
         </effectProxy>
         <effect name="extensioneffect" library="extensioneffect" uuid="fa81dd00-588b-11ed-9b6a-0242ac120002"/>
+        <effect name="acoustic_echo_canceler" library="aecsw" uuid="bb392ec0-8d4d-11e0-a896-0002a5d5c51b"/>
+        <effect name="noise_suppression" library="nssw" uuid="c06c8400-8e06-11e0-9cb6-0002a5d5c51b"/>
     </effects>
 
+    <preprocess>
+        <stream type="voice_communication">
+            <apply effect="acoustic_echo_canceler"/>
+            <apply effect="noise_suppression"/>
+        </stream>
+    </preprocess>
+
     <!-- Audio pre processor configurations.
          The pre processor configuration is described in a "preprocess" element and consists in a
          list of elements each describing pre processor settings for a given use case or "stream".
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectConfig.h b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
index c627a27..f8a86e1 100644
--- a/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
+++ b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
@@ -26,6 +26,7 @@
 #include <cutils/properties.h>
 #include <tinyxml2.h>
 
+#include <aidl/android/hardware/audio/effect/Processing.h>
 #include "effect-impl/EffectTypes.h"
 
 namespace aidl::android::hardware::audio::effect {
@@ -39,11 +40,6 @@
   public:
     explicit EffectConfig(const std::string& file);
 
-    // <library>
-    struct Library {
-        std::string name;
-        std::string path;
-    };
     struct LibraryUuid {
         std::string name;  // library name
         ::aidl::android::media::audio::common::AudioUuid uuid;
@@ -59,13 +55,13 @@
     const std::unordered_map<std::string, struct EffectLibraries> getEffectsMap() const {
         return mEffectsMap;
     }
-    const std::unordered_map<std::string, std::vector<std::string>> getProcessingMap() const {
-        return mProcessingMap;
-    }
 
     static bool findUuid(const std::string& xmlEffectName,
                          ::aidl::android::media::audio::common::AudioUuid* uuid);
 
+    using ProcessingLibrariesMap = std::map<Processing::Type, std::vector<struct EffectLibraries>>;
+    const ProcessingLibrariesMap& getProcessingMap() const;
+
   private:
     static constexpr const char* kEffectLibPath[] =
 #ifdef __LP64__
@@ -79,8 +75,11 @@
     std::unordered_map<std::string, std::string> mLibraryMap;
     /* Parsed Effects result */
     std::unordered_map<std::string, struct EffectLibraries> mEffectsMap;
-    /* Parsed pre/post processing result */
-    std::unordered_map<std::string, std::vector<std::string>> mProcessingMap;
+    /**
+     * For parsed pre/post processing result: {key: AudioStreamType/AudioSource, value:
+     * EffectLibraries}
+     */
+    ProcessingLibrariesMap mProcessingMap;
 
     /** @return all `node`s children that are elements and match the tag if provided. */
     std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> getChildren(
@@ -94,7 +93,7 @@
      */
     bool parseEffect(const tinyxml2::XMLElement& xml);
 
-    bool parseStream(const tinyxml2::XMLElement& xml);
+    bool parseProcessing(Processing::Type::Tag typeTag, const tinyxml2::XMLElement& xml);
 
     // Function to parse effect.library name and effect.uuid from xml
     bool parseLibraryUuid(const tinyxml2::XMLElement& xml, struct LibraryUuid& libraryUuid,
@@ -104,6 +103,9 @@
                      tinyxml2::XMLPrinter&& printer = {}) const;
 
     bool resolveLibrary(const std::string& path, std::string* resolvedPath);
+
+    std::optional<Processing::Type> stringToProcessingType(Processing::Type::Tag typeTag,
+                                                           const std::string& type);
 };
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
index b7f63af..ad59ca7 100644
--- a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
+++ b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
@@ -107,6 +107,10 @@
             const EffectConfig::LibraryUuid& configLib,
             const ::aidl::android::media::audio::common::AudioUuid& typeUuidStr,
             const std::optional<::aidl::android::media::audio::common::AudioUuid> proxyUuid);
+
+    ndk::ScopedAStatus getDescriptorWithUuid(
+            const aidl::android::media::audio::common::AudioUuid& uuid, Descriptor* desc);
+
     void loadEffectLibs();
     /* Get effect_dl_interface_s from library handle */
     void getDlSyms(DlEntry& entry);
diff --git a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
index 7b9477d..9cd6c22 100644
--- a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
@@ -267,6 +267,7 @@
 TEST_P(EffectFactoryTest, QueryProcess) {
     std::vector<Processing> processing;
     EXPECT_IS_OK(mEffectFactory->queryProcessing(std::nullopt, &processing));
+    std::set<Processing> processingSet(processing.begin(), processing.end());
 
     Processing::Type streamType =
             Processing::Type::make<Processing::Type::streamType>(AudioStreamType::SYSTEM);
@@ -279,7 +280,14 @@
     EXPECT_IS_OK(mEffectFactory->queryProcessing(source, &processingFilteredBySource));
 
     EXPECT_TRUE(processing.size() >= processingFilteredByStream.size());
+    EXPECT_TRUE(std::all_of(
+            processingFilteredByStream.begin(), processingFilteredByStream.end(),
+            [&](const auto& proc) { return processingSet.find(proc) != processingSet.end(); }));
+
     EXPECT_TRUE(processing.size() >= processingFilteredBySource.size());
+    EXPECT_TRUE(std::all_of(
+            processingFilteredBySource.begin(), processingFilteredBySource.end(),
+            [&](const auto& proc) { return processingSet.find(proc) != processingSet.end(); }));
 }
 
 INSTANTIATE_TEST_SUITE_P(EffectFactoryTest, EffectFactoryTest,
diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp
index f9a02ba..e1dfcfc 100644
--- a/keymaster/4.0/vts/functional/Android.bp
+++ b/keymaster/4.0/vts/functional/Android.bp
@@ -30,13 +30,17 @@
         "keymaster_hidl_hal_test.cpp",
     ],
     srcs: [
+        "BootloaderStateTest.cpp",
         "HmacKeySharingTest.cpp",
         "VerificationTokenTest.cpp",
         "keymaster_hidl_hal_test.cpp",
     ],
     static_libs: [
         "android.hardware.keymaster@4.0",
+        "libavb_user",
+        "libavb",
         "libcrypto_static",
+        "libfs_mgr",
         "libkeymaster4support",
         "libkeymaster4vtstest",
     ],
@@ -64,6 +68,7 @@
     ],
     static_libs: [
         "android.hardware.keymaster@4.0",
+        "libcrypto_static",
         "libkeymaster4support",
     ],
 }
diff --git a/keymaster/4.0/vts/functional/BootloaderStateTest.cpp b/keymaster/4.0/vts/functional/BootloaderStateTest.cpp
new file mode 100644
index 0000000..6b5e8bf
--- /dev/null
+++ b/keymaster/4.0/vts/functional/BootloaderStateTest.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include <android-base/properties.h>
+#include <fstab/fstab.h>
+#include <libavb/libavb.h>
+#include <libavb_user/avb_ops_user.h>
+
+#include "KeymasterHidlTest.h"
+
+namespace android::hardware::keymaster::V4_0::test {
+
+using ::std::string;
+using ::std::vector;
+
+// Since this test needs to talk to Keymaster HAL, it can only run as root. Thus,
+// bootloader can not be locked.
+class BootloaderStateTest : public KeymasterHidlTest {
+  public:
+    virtual void SetUp() override {
+        KeymasterHidlTest::SetUp();
+
+        // Generate a key.
+        auto ec = GenerateKey(AuthorizationSetBuilder()
+                                      .Authorization(TAG_NO_AUTH_REQUIRED)
+                                      .EcdsaSigningKey(EcCurve::P_256)
+                                      .Digest(Digest::SHA_2_256));
+        ASSERT_EQ(ec, ErrorCode::OK) << "Failed to generate key.";
+
+        // Generate attestation.
+        hidl_vec<hidl_vec<uint8_t>> cert_chain;
+        ec = AttestKey(AuthorizationSetBuilder()
+                               .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+                               .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+                       &cert_chain);
+        ASSERT_EQ(ec, ErrorCode::OK) << "Failed to generate attestation.";
+
+        X509_Ptr cert(parse_cert_blob(cert_chain[0]));
+        ASSERT_TRUE(cert.get()) << "Failed to parse certificate blob.";
+
+        ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
+        ASSERT_TRUE(attest_rec) << "Failed to get attestation record.";
+
+        // Parse root of trust.
+        HidlBuf verified_boot_key;
+        keymaster_verified_boot_t verified_boot_state;
+        bool device_locked;
+        HidlBuf verified_boot_hash;
+        auto result =
+                parse_root_of_trust(attest_rec->data, attest_rec->length, &verified_boot_key,
+                                    &verified_boot_state, &device_locked, &verified_boot_hash);
+        ASSERT_EQ(result, ErrorCode::OK) << "Failed to parse root of trust.";
+    }
+
+    hidl_vec<uint8_t> attestedVbKey_;
+    keymaster_verified_boot_t attestedVbState_;
+    bool attestedBootloaderState_;
+    hidl_vec<uint8_t> attestedVbmetaDigest_;
+};
+
+// Check that attested bootloader state is set to unlocked.
+TEST_P(BootloaderStateTest, BootloaderIsUnlocked) {
+    ASSERT_FALSE(attestedBootloaderState_)
+            << "This test runs as root. Bootloader must be unlocked.";
+}
+
+// Check that verified boot state is set to "unverified", i.e. "orange".
+TEST_P(BootloaderStateTest, VbStateIsUnverified) {
+    // Unlocked bootloader implies that verified boot state must be "unverified".
+    ASSERT_EQ(attestedVbState_, KM_VERIFIED_BOOT_UNVERIFIED)
+            << "Verified boot state must be \"UNVERIFIED\" aka \"orange\".";
+
+    // AVB spec stipulates that bootloader must set "androidboot.verifiedbootstate" parameter
+    // on the kernel command-line. This parameter is exposed to userspace as
+    // "ro.boot.verifiedbootstate" property.
+    auto vbStateProp = ::android::base::GetProperty("ro.boot.verifiedbootstate", "");
+    ASSERT_EQ(vbStateProp, "orange")
+            << "Verified boot state must be \"UNVERIFIED\" aka \"orange\".";
+}
+
+// Following error codes from avb_slot_data() mean that slot data was loaded
+// (even if verification failed).
+static inline bool avb_slot_data_loaded(AvbSlotVerifyResult result) {
+    switch (result) {
+        case AVB_SLOT_VERIFY_RESULT_OK:
+        case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
+        case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
+        case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
+            return true;
+        default:
+            return false;
+    }
+}
+
+// Check that attested vbmeta digest is correct.
+TEST_P(BootloaderStateTest, VbmetaDigest) {
+    AvbSlotVerifyData* avbSlotData;
+    auto suffix = fs_mgr_get_slot_suffix();
+    const char* partitions[] = {nullptr};
+    auto avbOps = avb_ops_user_new();
+
+    // For VTS, devices run with vendor_boot-debug.img, which is not release key
+    // signed. Use AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR to bypass avb
+    // verification errors. This is OK since we only care about the digest for
+    // this test case.
+    auto result = avb_slot_verify(avbOps, partitions, suffix.c_str(),
+                                  AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR,
+                                  AVB_HASHTREE_ERROR_MODE_EIO, &avbSlotData);
+    ASSERT_TRUE(avb_slot_data_loaded(result)) << "Failed to load avb slot data";
+
+    // Unfortunately, bootloader is not required to report the algorithm used
+    // to calculate the digest. There are only two supported options though,
+    // SHA256 and SHA512. Attested VBMeta digest must match one of these.
+    vector<uint8_t> digest256(AVB_SHA256_DIGEST_SIZE);
+    vector<uint8_t> digest512(AVB_SHA512_DIGEST_SIZE);
+
+    avb_slot_verify_data_calculate_vbmeta_digest(avbSlotData, AVB_DIGEST_TYPE_SHA256,
+                                                 digest256.data());
+    avb_slot_verify_data_calculate_vbmeta_digest(avbSlotData, AVB_DIGEST_TYPE_SHA512,
+                                                 digest512.data());
+
+    ASSERT_TRUE((attestedVbmetaDigest_ == digest256) || (attestedVbmetaDigest_ == digest512))
+            << "Attested digest does not match computed digest.";
+}
+
+INSTANTIATE_KEYMASTER_HIDL_TEST(BootloaderStateTest);
+
+}  // namespace android::hardware::keymaster::V4_0::test
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
index 315a4bd..e2ad0ef 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
@@ -841,6 +841,30 @@
     return {};
 }
 
+X509* parse_cert_blob(const hidl_vec<uint8_t>& blob) {
+    const uint8_t* p = blob.data();
+    return d2i_X509(nullptr, &p, blob.size());
+}
+
+ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
+    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+    EXPECT_TRUE(!!oid.get());
+    if (!oid.get()) return nullptr;
+
+    int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
+    EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
+    if (location == -1) return nullptr;
+
+    X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
+    EXPECT_TRUE(!!attest_rec_ext)
+            << "Found attestation extension but couldn't retrieve it?  Probably a BoringSSL bug.";
+    if (!attest_rec_ext) return nullptr;
+
+    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+    EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
+    return attest_rec;
+}
+
 }  // namespace test
 }  // namespace V4_0
 }  // namespace keymaster
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
index ad30aa7..67829ec 100644
--- a/keymaster/4.0/vts/functional/KeymasterHidlTest.h
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
@@ -22,7 +22,9 @@
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
 
+#include <keymasterV4_0/attestation_record.h>
 #include <keymasterV4_0/authorization_set.h>
+#include <keymasterV4_0/openssl_utils.h>
 
 namespace android {
 namespace hardware {
@@ -241,6 +243,11 @@
                              testing::ValuesIn(KeymasterHidlTest::build_params()), \
                              android::hardware::PrintInstanceNameToString)
 
+X509* parse_cert_blob(const hidl_vec<uint8_t>& blob);
+// Extract attestation record from cert. Returned object is still part of cert; don't free it
+// separately.
+ASN1_OCTET_STRING* get_attestation_record(X509* certificate);
+
 }  // namespace test
 }  // namespace V4_0
 }  // namespace keymaster
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 728cc91..b709904 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -263,11 +263,6 @@
     void operator()(RSA* p) { RSA_free(p); }
 };
 
-X509* parse_cert_blob(const hidl_vec<uint8_t>& blob) {
-    const uint8_t* p = blob.data();
-    return d2i_X509(nullptr, &p, blob.size());
-}
-
 bool verify_chain(const hidl_vec<hidl_vec<uint8_t>>& chain, const std::string& msg,
                   const std::string& signature) {
     {
@@ -337,27 +332,6 @@
     return true;
 }
 
-// Extract attestation record from cert. Returned object is still part of cert; don't free it
-// separately.
-ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
-    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
-    EXPECT_TRUE(!!oid.get());
-    if (!oid.get()) return nullptr;
-
-    int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
-    EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
-    if (location == -1) return nullptr;
-
-    X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
-    EXPECT_TRUE(!!attest_rec_ext)
-        << "Found attestation extension but couldn't retrieve it?  Probably a BoringSSL bug.";
-    if (!attest_rec_ext) return nullptr;
-
-    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
-    EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
-    return attest_rec;
-}
-
 bool tag_in_list(const KeyParameter& entry) {
     // Attestations don't contain everything in key authorization lists, so we need to filter
     // the key lists to produce the lists that we expect to match the attestations.
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index 7a4359d..41b161d 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -43,8 +43,11 @@
         "android.hardware.gatekeeper-V1-ndk",
         "android.hardware.security.rkp-V3-ndk",
         "android.hardware.security.secureclock-V1-ndk",
+        "libavb_user",
+        "libavb",
         "libcppbor_external",
         "libcppcose_rkp",
+        "libfs_mgr",
         "libjsoncpp",
         "libkeymint",
         "libkeymint_remote_prov_support",
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index e759123..c035f19 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -88,96 +88,9 @@
 class AttestKeyTest : public KeyMintAidlTestBase {
   public:
     void SetUp() override {
-        check_skip_test();
+        skipAttestKeyTest();
         KeyMintAidlTestBase::SetUp();
     }
-
-  protected:
-    const string FEATURE_KEYSTORE_APP_ATTEST_KEY = "android.hardware.keystore.app_attest_key";
-
-    const string FEATURE_STRONGBOX_KEYSTORE = "android.hardware.strongbox_keystore";
-
-    ErrorCode GenerateAttestKey(const AuthorizationSet& key_desc,
-                                const optional<AttestationKey>& attest_key,
-                                vector<uint8_t>* key_blob,
-                                vector<KeyCharacteristics>* key_characteristics,
-                                vector<Certificate>* cert_chain) {
-        // The original specification for KeyMint v1 required ATTEST_KEY not be combined
-        // with any other key purpose, but the original VTS tests incorrectly did exactly that.
-        // This means that a device that launched prior to Android T (API level 33) may
-        // accept or even require KeyPurpose::SIGN too.
-        if (property_get_int32("ro.board.first_api_level", 0) < __ANDROID_API_T__) {
-            AuthorizationSet key_desc_plus_sign = key_desc;
-            key_desc_plus_sign.push_back(TAG_PURPOSE, KeyPurpose::SIGN);
-
-            auto result = GenerateKey(key_desc_plus_sign, attest_key, key_blob, key_characteristics,
-                                      cert_chain);
-            if (result == ErrorCode::OK) {
-                return result;
-            }
-            // If the key generation failed, it may be because the device is (correctly)
-            // rejecting the combination of ATTEST_KEY+SIGN.  Fall through to try again with
-            // just ATTEST_KEY.
-        }
-        return GenerateKey(key_desc, attest_key, key_blob, key_characteristics, cert_chain);
-    }
-
-    // Check if ATTEST_KEY feature is disabled
-    bool is_attest_key_feature_disabled(void) const {
-        if (!check_feature(FEATURE_KEYSTORE_APP_ATTEST_KEY)) {
-            GTEST_LOG_(INFO) << "Feature " + FEATURE_KEYSTORE_APP_ATTEST_KEY + " is disabled";
-            return true;
-        }
-
-        return false;
-    }
-
-    // Check if StrongBox KeyStore is enabled
-    bool is_strongbox_enabled(void) const {
-        if (check_feature(FEATURE_STRONGBOX_KEYSTORE)) {
-            GTEST_LOG_(INFO) << "Feature " + FEATURE_STRONGBOX_KEYSTORE + " is enabled";
-            return true;
-        }
-
-        return false;
-    }
-
-    // Check if chipset has received a waiver allowing it to be launched with Android S or T with
-    // Keymaster 4.0 in StrongBox.
-    bool is_chipset_allowed_km4_strongbox(void) const {
-        std::array<char, PROPERTY_VALUE_MAX> buffer;
-
-        const int32_t first_api_level = property_get_int32("ro.board.first_api_level", 0);
-        if (first_api_level <= 0 || first_api_level > __ANDROID_API_T__) return false;
-
-        auto res = property_get("ro.vendor.qti.soc_model", buffer.data(), nullptr);
-        if (res <= 0) return false;
-
-        const string allowed_soc_models[] = {"SM8450", "SM8475", "SM8550", "SXR2230P"};
-
-        for (const string model : allowed_soc_models) {
-            if (model.compare(buffer.data()) == 0) {
-                GTEST_LOG_(INFO) << "QTI SOC Model " + model + " is allowed SB KM 4.0";
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    // Skip the test if all the following conditions hold:
-    // 1. ATTEST_KEY feature is disabled
-    // 2. STRONGBOX is enabled
-    // 3. The device is running one of the chipsets that have received a waiver
-    //     allowing it to be launched with Android S (or later) with Keymaster 4.0
-    //     in StrongBox
-    void check_skip_test(void) const {
-        // Check the chipset first as that doesn't require a round-trip to Package Manager.
-        if (is_chipset_allowed_km4_strongbox() && is_strongbox_enabled() &&
-            is_attest_key_feature_disabled()) {
-            GTEST_SKIP() << "Test is not applicable";
-        }
-    }
 };
 
 /*
diff --git a/security/keymint/aidl/vts/functional/BootloaderStateTest.cpp b/security/keymint/aidl/vts/functional/BootloaderStateTest.cpp
index 723edee..54f187c 100644
--- a/security/keymint/aidl/vts/functional/BootloaderStateTest.cpp
+++ b/security/keymint/aidl/vts/functional/BootloaderStateTest.cpp
@@ -21,7 +21,11 @@
 #include <string>
 #include <vector>
 
+#include <android-base/properties.h>
 #include <android/binder_manager.h>
+#include <fstab/fstab.h>
+#include <libavb/libavb.h>
+#include <libavb_user/avb_ops_user.h>
 #include <remote_prov/remote_prov_utils.h>
 
 #include "KeyMintAidlTestBase.h"
@@ -34,49 +38,118 @@
 
 // Since this test needs to talk to KeyMint HAL, it can only run as root. Thus,
 // bootloader can not be locked.
-class BootloaderStateTest : public testing::TestWithParam<std::string> {
+class BootloaderStateTest : public KeyMintAidlTestBase {
   public:
     virtual void SetUp() override {
-        ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
-        keyMint_ = IKeyMintDevice::fromBinder(binder);
-        ASSERT_TRUE(keyMint_) << "Failed to get KM device";
+        KeyMintAidlTestBase::SetUp();
+
+        // Generate a key with attestation.
+        vector<uint8_t> key_blob;
+        vector<KeyCharacteristics> key_characteristics;
+        AuthorizationSet keyDesc = AuthorizationSetBuilder()
+                                           .Authorization(TAG_NO_AUTH_REQUIRED)
+                                           .EcdsaSigningKey(EcCurve::P_256)
+                                           .AttestationChallenge("foo")
+                                           .AttestationApplicationId("bar")
+                                           .Digest(Digest::NONE)
+                                           .SetDefaultValidity();
+        auto result = GenerateKey(keyDesc, &key_blob, &key_characteristics);
+        // If factory provisioned attestation key is not supported by Strongbox,
+        // then create a key with self-signed attestation and use it as the
+        // attestation key instead.
+        if (SecLevel() == SecurityLevel::STRONGBOX &&
+            result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) {
+            result = GenerateKeyWithSelfSignedAttestKey(
+                    AuthorizationSetBuilder()
+                            .EcdsaKey(EcCurve::P_256)
+                            .AttestKey()
+                            .SetDefaultValidity(), /* attest key params */
+                    keyDesc, &key_blob, &key_characteristics);
+        }
+        ASSERT_EQ(ErrorCode::OK, result);
+
+        // Parse attested AVB values.
+        X509_Ptr cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+        ASSERT_TRUE(cert.get());
+
+        ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
+        ASSERT_TRUE(attest_rec);
+
+        auto error = parse_root_of_trust(attest_rec->data, attest_rec->length, &attestedVbKey_,
+                                         &attestedVbState_, &attestedBootloaderState_,
+                                         &attestedVbmetaDigest_);
+        ASSERT_EQ(error, ErrorCode::OK);
     }
 
-    std::shared_ptr<IKeyMintDevice> keyMint_;
+    vector<uint8_t> attestedVbKey_;
+    VerifiedBoot attestedVbState_;
+    bool attestedBootloaderState_;
+    vector<uint8_t> attestedVbmetaDigest_;
 };
 
 // Check that attested bootloader state is set to unlocked.
-TEST_P(BootloaderStateTest, IsUnlocked) {
-    // Generate a key with attestation.
-    AuthorizationSet keyDesc = AuthorizationSetBuilder()
-                                       .Authorization(TAG_NO_AUTH_REQUIRED)
-                                       .EcdsaSigningKey(EcCurve::P_256)
-                                       .AttestationChallenge("foo")
-                                       .AttestationApplicationId("bar")
-                                       .Digest(Digest::NONE)
-                                       .SetDefaultValidity();
-    KeyCreationResult creationResult;
-    auto kmStatus = keyMint_->generateKey(keyDesc.vector_data(), std::nullopt, &creationResult);
-    ASSERT_TRUE(kmStatus.isOk());
+TEST_P(BootloaderStateTest, BootloaderIsUnlocked) {
+    ASSERT_FALSE(attestedBootloaderState_)
+            << "This test runs as root. Bootloader must be unlocked.";
+}
 
-    vector<Certificate> key_cert_chain = std::move(creationResult.certificateChain);
+// Check that verified boot state is set to "unverified", i.e. "orange".
+TEST_P(BootloaderStateTest, VbStateIsUnverified) {
+    // Unlocked bootloader implies that verified boot state must be "unverified".
+    ASSERT_EQ(attestedVbState_, VerifiedBoot::UNVERIFIED)
+            << "Verified boot state must be \"UNVERIFIED\" aka \"orange\".";
 
-    // Parse attested AVB values.
-    const auto& attestation_cert = key_cert_chain[0].encodedCertificate;
-    X509_Ptr cert(parse_cert_blob(attestation_cert));
-    ASSERT_TRUE(cert.get());
+    // AVB spec stipulates that bootloader must set "androidboot.verifiedbootstate" parameter
+    // on the kernel command-line. This parameter is exposed to userspace as
+    // "ro.boot.verifiedbootstate" property.
+    auto vbStateProp = ::android::base::GetProperty("ro.boot.verifiedbootstate", "");
+    ASSERT_EQ(vbStateProp, "orange")
+            << "Verified boot state must be \"UNVERIFIED\" aka \"orange\".";
+}
 
-    ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
-    ASSERT_TRUE(attest_rec);
+// Following error codes from avb_slot_data() mean that slot data was loaded
+// (even if verification failed).
+static inline bool avb_slot_data_loaded(AvbSlotVerifyResult result) {
+    switch (result) {
+        case AVB_SLOT_VERIFY_RESULT_OK:
+        case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
+        case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
+        case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
+            return true;
+        default:
+            return false;
+    }
+}
 
-    vector<uint8_t> key;
-    VerifiedBoot attestedVbState;
-    bool attestedBootloaderState;
-    vector<uint8_t> attestedVbmetaDigest;
-    auto error = parse_root_of_trust(attest_rec->data, attest_rec->length, &key, &attestedVbState,
-                                     &attestedBootloaderState, &attestedVbmetaDigest);
-    ASSERT_EQ(error, ErrorCode::OK);
-    ASSERT_FALSE(attestedBootloaderState) << "This test runs as root. Bootloader must be unlocked.";
+// Check that attested vbmeta digest is correct.
+TEST_P(BootloaderStateTest, VbmetaDigest) {
+    AvbSlotVerifyData* avbSlotData;
+    auto suffix = fs_mgr_get_slot_suffix();
+    const char* partitions[] = {nullptr};
+    auto avbOps = avb_ops_user_new();
+
+    // For VTS, devices run with vendor_boot-debug.img, which is not release key
+    // signed. Use AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR to bypass avb
+    // verification errors. This is OK since we only care about the digest for
+    // this test case.
+    auto result = avb_slot_verify(avbOps, partitions, suffix.c_str(),
+                                  AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR,
+                                  AVB_HASHTREE_ERROR_MODE_EIO, &avbSlotData);
+    ASSERT_TRUE(avb_slot_data_loaded(result)) << "Failed to load avb slot data";
+
+    // Unfortunately, bootloader is not required to report the algorithm used
+    // to calculate the digest. There are only two supported options though,
+    // SHA256 and SHA512. Attested VBMeta digest must match one of these.
+    vector<uint8_t> digest256(AVB_SHA256_DIGEST_SIZE);
+    vector<uint8_t> digest512(AVB_SHA512_DIGEST_SIZE);
+
+    avb_slot_verify_data_calculate_vbmeta_digest(avbSlotData, AVB_DIGEST_TYPE_SHA256,
+                                                 digest256.data());
+    avb_slot_verify_data_calculate_vbmeta_digest(avbSlotData, AVB_DIGEST_TYPE_SHA512,
+                                                 digest512.data());
+
+    ASSERT_TRUE((attestedVbmetaDigest_ == digest256) || (attestedVbmetaDigest_ == digest512))
+            << "Attested digest does not match computed digest.";
 }
 
 INSTANTIATE_KEYMINT_AIDL_TEST(BootloaderStateTest);
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 5e27bd0..a8ea407 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -322,12 +322,13 @@
         const AuthorizationSet& attest_key_desc, const AuthorizationSet& key_desc,
         vector<uint8_t>* key_blob, vector<KeyCharacteristics>* key_characteristics,
         vector<Certificate>* cert_chain) {
+    skipAttestKeyTest();
     AttestationKey attest_key;
     vector<Certificate> attest_cert_chain;
     vector<KeyCharacteristics> attest_key_characteristics;
     // Generate a key with self signed attestation.
-    auto error = GenerateKey(attest_key_desc, std::nullopt, &attest_key.keyBlob,
-                             &attest_key_characteristics, &attest_cert_chain);
+    auto error = GenerateAttestKey(attest_key_desc, std::nullopt, &attest_key.keyBlob,
+                                   &attest_key_characteristics, &attest_cert_chain);
     if (error != ErrorCode::OK) {
         return error;
     }
@@ -1548,6 +1549,88 @@
     return result;
 }
 
+ErrorCode KeyMintAidlTestBase::GenerateAttestKey(const AuthorizationSet& key_desc,
+                                                 const optional<AttestationKey>& attest_key,
+                                                 vector<uint8_t>* key_blob,
+                                                 vector<KeyCharacteristics>* key_characteristics,
+                                                 vector<Certificate>* cert_chain) {
+    // The original specification for KeyMint v1 required ATTEST_KEY not be combined
+    // with any other key purpose, but the original VTS tests incorrectly did exactly that.
+    // This means that a device that launched prior to Android T (API level 33) may
+    // accept or even require KeyPurpose::SIGN too.
+    if (property_get_int32("ro.board.first_api_level", 0) < __ANDROID_API_T__) {
+        AuthorizationSet key_desc_plus_sign = key_desc;
+        key_desc_plus_sign.push_back(TAG_PURPOSE, KeyPurpose::SIGN);
+
+        auto result = GenerateKey(key_desc_plus_sign, attest_key, key_blob, key_characteristics,
+                                  cert_chain);
+        if (result == ErrorCode::OK) {
+            return result;
+        }
+        // If the key generation failed, it may be because the device is (correctly)
+        // rejecting the combination of ATTEST_KEY+SIGN.  Fall through to try again with
+        // just ATTEST_KEY.
+    }
+    return GenerateKey(key_desc, attest_key, key_blob, key_characteristics, cert_chain);
+}
+
+// Check if ATTEST_KEY feature is disabled
+bool KeyMintAidlTestBase::is_attest_key_feature_disabled(void) const {
+    if (!check_feature(FEATURE_KEYSTORE_APP_ATTEST_KEY)) {
+        GTEST_LOG_(INFO) << "Feature " + FEATURE_KEYSTORE_APP_ATTEST_KEY + " is disabled";
+        return true;
+    }
+
+    return false;
+}
+
+// Check if StrongBox KeyStore is enabled
+bool KeyMintAidlTestBase::is_strongbox_enabled(void) const {
+    if (check_feature(FEATURE_STRONGBOX_KEYSTORE)) {
+        GTEST_LOG_(INFO) << "Feature " + FEATURE_STRONGBOX_KEYSTORE + " is enabled";
+        return true;
+    }
+
+    return false;
+}
+
+// Check if chipset has received a waiver allowing it to be launched with Android S or T with
+// Keymaster 4.0 in StrongBox.
+bool KeyMintAidlTestBase::is_chipset_allowed_km4_strongbox(void) const {
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+
+    const int32_t first_api_level = property_get_int32("ro.board.first_api_level", 0);
+    if (first_api_level <= 0 || first_api_level > __ANDROID_API_T__) return false;
+
+    auto res = property_get("ro.vendor.qti.soc_model", buffer.data(), nullptr);
+    if (res <= 0) return false;
+
+    const string allowed_soc_models[] = {"SM8450", "SM8475", "SM8550", "SXR2230P"};
+
+    for (const string model : allowed_soc_models) {
+        if (model.compare(buffer.data()) == 0) {
+            GTEST_LOG_(INFO) << "QTI SOC Model " + model + " is allowed SB KM 4.0";
+            return true;
+        }
+    }
+
+    return false;
+}
+
+// Skip the test if all the following conditions hold:
+// 1. ATTEST_KEY feature is disabled
+// 2. STRONGBOX is enabled
+// 3. The device is running one of the chipsets that have received a waiver
+//     allowing it to be launched with Android S (or later) with Keymaster 4.0
+//     in StrongBox
+void KeyMintAidlTestBase::skipAttestKeyTest(void) const {
+    // Check the chipset first as that doesn't require a round-trip to Package Manager.
+    if (is_chipset_allowed_km4_strongbox() && is_strongbox_enabled() &&
+        is_attest_key_feature_disabled()) {
+        GTEST_SKIP() << "Test is not applicable";
+    }
+}
+
 void verify_serial(X509* cert, const uint64_t expected_serial) {
     BIGNUM_Ptr ser(BN_new());
     EXPECT_TRUE(ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), ser.get()));
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 3245ca9..30ac452 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -54,6 +54,9 @@
 
 constexpr uint64_t kOpHandleSentinel = 0xFFFFFFFFFFFFFFFF;
 
+const string FEATURE_KEYSTORE_APP_ATTEST_KEY = "android.hardware.keystore.app_attest_key";
+const string FEATURE_STRONGBOX_KEYSTORE = "android.hardware.strongbox_keystore";
+
 class KeyMintAidlTestBase : public ::testing::TestWithParam<string> {
   public:
     struct KeyData {
@@ -347,6 +350,17 @@
     ErrorCode UseRsaKey(const vector<uint8_t>& rsaKeyBlob);
     ErrorCode UseEcdsaKey(const vector<uint8_t>& ecdsaKeyBlob);
 
+    ErrorCode GenerateAttestKey(const AuthorizationSet& key_desc,
+                                const optional<AttestationKey>& attest_key,
+                                vector<uint8_t>* key_blob,
+                                vector<KeyCharacteristics>* key_characteristics,
+                                vector<Certificate>* cert_chain);
+
+    bool is_attest_key_feature_disabled(void) const;
+    bool is_strongbox_enabled(void) const;
+    bool is_chipset_allowed_km4_strongbox(void) const;
+    void skipAttestKeyTest(void) const;
+
   protected:
     std::shared_ptr<IKeyMintDevice> keymint_;
     uint32_t os_version_;