Merge "identity: add TEST_MAPPING file to run CTS, VTS, and unit tests in presubmit."
diff --git a/audio/7.0/config/api/current.txt b/audio/7.0/config/api/current.txt
index 48093c5..eb8c2dd 100644
--- a/audio/7.0/config/api/current.txt
+++ b/audio/7.0/config/api/current.txt
@@ -155,6 +155,12 @@
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADSET;
   }
 
+  public enum AudioEncapsulationType {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.configuration.V7_0.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_IEC61937;
+    enum_constant public static final android.audio.policy.configuration.V7_0.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_NONE;
+  }
+
   public enum AudioFormat {
     method @NonNull public String getRawName();
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC;
@@ -487,10 +493,12 @@
   public class Profile {
     ctor public Profile();
     method @Nullable public java.util.List<android.audio.policy.configuration.V7_0.AudioChannelMask> getChannelMasks();
+    method @Nullable public android.audio.policy.configuration.V7_0.AudioEncapsulationType getEncapsulationType();
     method @Nullable public String getFormat();
     method @Nullable public String getName();
     method @Nullable public java.util.List<java.math.BigInteger> getSamplingRates();
     method public void setChannelMasks(@Nullable java.util.List<android.audio.policy.configuration.V7_0.AudioChannelMask>);
+    method public void setEncapsulationType(@Nullable android.audio.policy.configuration.V7_0.AudioEncapsulationType);
     method public void setFormat(@Nullable String);
     method public void setName(@Nullable String);
     method public void setSamplingRates(@Nullable java.util.List<java.math.BigInteger>);
diff --git a/audio/7.0/config/audio_policy_configuration.xsd b/audio/7.0/config/audio_policy_configuration.xsd
index ccaaf98..007e250 100644
--- a/audio/7.0/config/audio_policy_configuration.xsd
+++ b/audio/7.0/config/audio_policy_configuration.xsd
@@ -550,11 +550,18 @@
     <xs:simpleType name="channelMasks">
         <xs:list itemType="audioChannelMask" />
     </xs:simpleType>
+    <xs:simpleType name="audioEncapsulationType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_NONE"/>
+            <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_IEC61937"/>
+        </xs:restriction>
+    </xs:simpleType>
     <xs:complexType name="profile">
         <xs:attribute name="name" type="xs:token" use="optional"/>
         <xs:attribute name="format" type="extendableAudioFormat" use="optional"/>
         <xs:attribute name="samplingRates" type="samplingRates" use="optional"/>
         <xs:attribute name="channelMasks" type="channelMasks" use="optional"/>
+        <xs:attribute name="encapsulationType" type="audioEncapsulationType" use="optional"/>
     </xs:complexType>
     <xs:simpleType name="audioGainMode">
         <xs:restriction base="xs:string">
diff --git a/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h b/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h
index 88dd12e..7d83556 100644
--- a/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h
+++ b/audio/common/7.0/enums/include/android_audio_policy_configuration_V7_0-enums.h
@@ -287,6 +287,10 @@
     return isLinearPcm(stringToAudioFormat(format));
 }
 
+static inline bool isUnknownAudioEncapsulationType(const std::string& encapsulationType) {
+    return stringToAudioEncapsulationType(encapsulationType) == AudioEncapsulationType::UNKNOWN;
+}
+
 }  // namespace android::audio::policy::configuration::V7_0
 
 #endif  // ANDROID_AUDIO_POLICY_CONFIGURATION_V7_0__ENUMS_H
diff --git a/audio/common/7.0/types.hal b/audio/common/7.0/types.hal
index 4f920e4..6fca93e 100644
--- a/audio/common/7.0/types.hal
+++ b/audio/common/7.0/types.hal
@@ -145,6 +145,14 @@
 };
 
 /**
+ * Audio encapsulation type indicates the encapsulation type that is required
+ * for playback/capture.
+ * See 'audioEncapsulationType' in audio_policy_configuration.xsd for the list
+ * of allowed values.
+ */
+typedef string AudioEncapsulationType;
+
+/**
  * Configurations supported for a certain audio format.
  */
 struct AudioProfile {
@@ -156,6 +164,35 @@
 };
 
 /**
+ * AudioTransport struct describes the capability of an audio port. The
+ * capability is described via AudioProfile or raw hardware descriptors for
+ * for formats that are not supported by the platform.
+ */
+struct AudioTransport {
+    safe_union AudioCapability {
+        /**
+         * A certain audio format that is known by the platform and its
+         * corresponding configuration.
+         */
+        AudioProfile profile;
+        /**
+         * The audio descriptor that is reported from EDID. See HDMI
+         * specification 1.4b section 7 and CEA-861-G section 7.5.2 for more
+         * information. When this value is set, it indicates the standard is
+         * AUDIO_STANDARD_EDID.
+         */
+        vec<uint8_t> edid;
+    } audioCapability;
+
+    /**
+     * The encapsulation type that is required when the framework is using this
+     * format when playing or capturing to/from a stream or device exposing this
+     * audio transport.
+     */
+    AudioEncapsulationType encapsulationType;
+};
+
+/**
  * Major modes for a mobile device. The current mode setting affects audio
  * routing.
  */
@@ -488,8 +525,12 @@
      * E.g. "telephony_tx" or "fm_tuner".
      */
     string name;
-    /** List of audio profiles supported by the port. */
-    vec<AudioProfile> profiles;
+    /**
+     * List of audio transports supported by the audio port. This includes
+     * supported formats and raw hardware descriptors for formats not supported
+     * by the platform.
+     */
+    vec<AudioTransport> transports;
     /** List of gain controls attached to the port. */
     vec<AudioGain> gains;
     /** Parameters that depend on the actual port role. */
diff --git a/audio/common/all-versions/default/7.0/HidlUtils.cpp b/audio/common/all-versions/default/7.0/HidlUtils.cpp
index 2949fac..5a5b5d2 100644
--- a/audio/common/all-versions/default/7.0/HidlUtils.cpp
+++ b/audio/common/all-versions/default/7.0/HidlUtils.cpp
@@ -715,6 +715,27 @@
     return result;
 }
 
+status_t HidlUtils::encapsulationTypeFromHal(audio_encapsulation_type_t halEncapsulationType,
+                                             AudioEncapsulationType* encapsulationType) {
+    *encapsulationType = audio_encapsulation_type_to_string(halEncapsulationType);
+    if (!encapsulationType->empty() && !xsd::isUnknownAudioEncapsulationType(*encapsulationType)) {
+        return NO_ERROR;
+    }
+    ALOGE("Unknown audio encapsulation type value 0x%X", halEncapsulationType);
+    return BAD_VALUE;
+}
+
+status_t HidlUtils::encapsulationTypeToHal(const AudioEncapsulationType& encapsulationType,
+                                           audio_encapsulation_type_t* halEncapsulationType) {
+    if (!xsd::isUnknownAudioEncapsulationType(encapsulationType) &&
+        audio_encapsulation_type_from_string(encapsulationType.c_str(), halEncapsulationType)) {
+        return NO_ERROR;
+    }
+    ALOGE("Unknown audio encapsulation type \"%s\"", encapsulationType.c_str());
+    *halEncapsulationType = AUDIO_ENCAPSULATION_TYPE_NONE;
+    return BAD_VALUE;
+}
+
 status_t HidlUtils::audioPortFromHal(const struct audio_port& halPort, AudioPort* port) {
     struct audio_port_v7 halPortV7 = {};
     audio_populate_audio_port_v7(&halPort, &halPortV7);
@@ -758,11 +779,7 @@
     CONVERT_CHECKED(audioPortExtendedInfoFromHal(halPort.role, halPort.type, halDevice, halMix,
                                                  halSession, &port->ext, &isInput),
                     result);
-    port->profiles.resize(halPort.num_audio_profiles);
-    for (size_t i = 0; i < halPort.num_audio_profiles; ++i) {
-        CONVERT_CHECKED(audioProfileFromHal(halPort.audio_profiles[i], isInput, &port->profiles[i]),
-                        result);
-    }
+    CONVERT_CHECKED(audioTransportsFromHal(halPort, isInput, &port->transports), result);
     port->gains.resize(halPort.num_gains);
     for (size_t i = 0; i < halPort.num_gains; ++i) {
         CONVERT_CHECKED(audioGainFromHal(halPort.gains[i], isInput, &port->gains[i]), result);
@@ -780,15 +797,7 @@
         ALOGE("HIDL Audio Port name is too long: %zu", port.name.size());
         result = BAD_VALUE;
     }
-    halPort->num_audio_profiles = port.profiles.size();
-    if (halPort->num_audio_profiles > AUDIO_PORT_MAX_AUDIO_PROFILES) {
-        ALOGE("HIDL Audio Port has too many profiles: %u", halPort->num_audio_profiles);
-        halPort->num_audio_profiles = AUDIO_PORT_MAX_AUDIO_PROFILES;
-        result = BAD_VALUE;
-    }
-    for (size_t i = 0; i < halPort->num_audio_profiles; ++i) {
-        CONVERT_CHECKED(audioProfileToHal(port.profiles[i], &halPort->audio_profiles[i]), result);
-    }
+    CONVERT_CHECKED(audioTransportsToHal(port.transports, halPort), result);
     halPort->num_gains = port.gains.size();
     if (halPort->num_gains > AUDIO_PORT_MAX_GAINS) {
         ALOGE("HIDL Audio Port has too many gains: %u", halPort->num_gains);
@@ -824,6 +833,110 @@
     return result;
 }
 
+status_t HidlUtils::audioTransportsFromHal(const struct audio_port_v7& halPort, bool isInput,
+                                           hidl_vec<AudioTransport>* transports) {
+    if (halPort.num_audio_profiles > AUDIO_PORT_MAX_AUDIO_PROFILES ||
+        halPort.num_extra_audio_descriptors > AUDIO_PORT_MAX_EXTRA_AUDIO_DESCRIPTORS) {
+        ALOGE("%s, too many audio profiles(%u) or extra audio descriptors(%u)", __func__,
+              halPort.num_audio_profiles, halPort.num_extra_audio_descriptors);
+        return BAD_VALUE;
+    }
+    status_t result = NO_ERROR;
+    transports->resize(halPort.num_audio_profiles + halPort.num_extra_audio_descriptors);
+    size_t idx = 0;
+    for (size_t i = 0; i < halPort.num_audio_profiles; ++i) {
+        auto& transport = (*transports)[idx++];
+        transport.audioCapability.profile({});
+        CONVERT_CHECKED(audioProfileFromHal(halPort.audio_profiles[i], isInput,
+                                            &transport.audioCapability.profile()),
+                        result);
+        CONVERT_CHECKED(encapsulationTypeFromHal(halPort.audio_profiles[i].encapsulation_type,
+                                                 &transport.encapsulationType),
+                        result);
+    }
+    for (size_t i = 0; i < halPort.num_extra_audio_descriptors; ++i) {
+        switch (halPort.extra_audio_descriptors[i].standard) {
+            case AUDIO_STANDARD_EDID: {
+                const struct audio_extra_audio_descriptor* extraAudioDescriptor =
+                        &halPort.extra_audio_descriptors[i];
+                if (extraAudioDescriptor->descriptor_length <= EXTRA_AUDIO_DESCRIPTOR_SIZE) {
+                    auto& transport = (*transports)[idx++];
+                    transport.audioCapability.edid(
+                            hidl_vec<uint8_t>(extraAudioDescriptor->descriptor,
+                                              extraAudioDescriptor->descriptor +
+                                                      extraAudioDescriptor->descriptor_length));
+                    CONVERT_CHECKED(
+                            encapsulationTypeFromHal(extraAudioDescriptor->encapsulation_type,
+                                                     &transport.encapsulationType),
+                            result);
+                } else {
+                    ALOGE("%s, invalid descriptor length %u", __func__,
+                          extraAudioDescriptor->descriptor_length);
+                    result = BAD_VALUE;
+                }
+            } break;
+            case AUDIO_STANDARD_NONE:
+            default:
+                ALOGE("%s, invalid standard %u", __func__,
+                      halPort.extra_audio_descriptors[i].standard);
+                result = BAD_VALUE;
+                break;
+        }
+    }
+    return result;
+}
+
+status_t HidlUtils::audioTransportsToHal(const hidl_vec<AudioTransport>& transports,
+                                         struct audio_port_v7* halPort) {
+    status_t result = NO_ERROR;
+    halPort->num_audio_profiles = 0;
+    halPort->num_extra_audio_descriptors = 0;
+    for (const auto& transport : transports) {
+        switch (transport.audioCapability.getDiscriminator()) {
+            case AudioTransport::AudioCapability::hidl_discriminator::profile:
+                if (halPort->num_audio_profiles > AUDIO_PORT_MAX_AUDIO_PROFILES) {
+                    ALOGE("%s, too many audio profiles", __func__);
+                    result = BAD_VALUE;
+                    break;
+                }
+                CONVERT_CHECKED(
+                        audioProfileToHal(transport.audioCapability.profile(),
+                                          &halPort->audio_profiles[halPort->num_audio_profiles]),
+                        result);
+                CONVERT_CHECKED(encapsulationTypeToHal(
+                                        transport.encapsulationType,
+                                        &halPort->audio_profiles[halPort->num_audio_profiles++]
+                                                 .encapsulation_type),
+                                result);
+                break;
+            case AudioTransport::AudioCapability::hidl_discriminator::edid:
+                if (halPort->num_extra_audio_descriptors > AUDIO_PORT_MAX_EXTRA_AUDIO_DESCRIPTORS) {
+                    ALOGE("%s, too many extra audio descriptors", __func__);
+                    result = BAD_VALUE;
+                    break;
+                }
+                if (transport.audioCapability.edid().size() > EXTRA_AUDIO_DESCRIPTOR_SIZE) {
+                    ALOGE("%s, wrong edid size %zu", __func__,
+                          transport.audioCapability.edid().size());
+                    result = BAD_VALUE;
+                    break;
+                }
+                struct audio_extra_audio_descriptor* extraAudioDescriptor =
+                        &halPort->extra_audio_descriptors[halPort->num_extra_audio_descriptors++];
+                extraAudioDescriptor->standard = AUDIO_STANDARD_EDID;
+                extraAudioDescriptor->descriptor_length = transport.audioCapability.edid().size();
+                memcpy(extraAudioDescriptor->descriptor, transport.audioCapability.edid().data(),
+                       transport.audioCapability.edid().size() * sizeof(uint8_t));
+
+                CONVERT_CHECKED(encapsulationTypeToHal(transport.encapsulationType,
+                                                       &extraAudioDescriptor->encapsulation_type),
+                                result);
+                break;
+        }
+    }
+    return result;
+}
+
 status_t HidlUtils::audioProfileFromHal(const struct audio_profile& halProfile, bool isInput,
                                         AudioProfile* profile) {
     status_t result = NO_ERROR;
diff --git a/audio/common/all-versions/default/HidlUtils.h b/audio/common/all-versions/default/HidlUtils.h
index dd4ca4d..98ecc07 100644
--- a/audio/common/all-versions/default/HidlUtils.h
+++ b/audio/common/all-versions/default/HidlUtils.h
@@ -126,6 +126,10 @@
     static hidl_vec<AudioTag> filterOutNonVendorTags(const hidl_vec<AudioTag>& tags);
     static std::vector<std::string> filterOutNonVendorTags(const std::vector<std::string>& tags);
     static std::vector<std::string> splitAudioTags(const char* halTags);
+    static status_t audioTransportsFromHal(const struct audio_port_v7& halPort, bool isInput,
+                                           hidl_vec<AudioTransport>* transports);
+    static status_t audioTransportsToHal(const hidl_vec<AudioTransport>& transports,
+                                         struct audio_port_v7* halTransport);
 
   private:
     static status_t audioIndexChannelMaskFromHal(audio_channel_mask_t halChannelMask,
@@ -145,6 +149,10 @@
                                                struct audio_port_config_device_ext* device,
                                                struct audio_port_config_mix_ext* mix,
                                                struct audio_port_config_session_ext* session);
+    static status_t encapsulationTypeFromHal(audio_encapsulation_type_t halEncapsulationType,
+                                             AudioEncapsulationType* encapsulationType);
+    static status_t encapsulationTypeToHal(const AudioEncapsulationType& encapsulationType,
+                                           audio_encapsulation_type_t* halEncapsulationType);
 
 #endif  // MAJOR_VERSION >= 7
 
diff --git a/audio/common/all-versions/default/tests/hidlutils_tests.cpp b/audio/common/all-versions/default/tests/hidlutils_tests.cpp
index e154453..c9e6fac 100644
--- a/audio/common/all-versions/default/tests/hidlutils_tests.cpp
+++ b/audio/common/all-versions/default/tests/hidlutils_tests.cpp
@@ -47,6 +47,10 @@
 // AUDIO_STREAM_DEFAULT is framework-only
 static constexpr audio_stream_type_t kInvalidHalStreamType = static_cast<audio_stream_type_t>(-2);
 static constexpr audio_usage_t kInvalidHalUsage = static_cast<audio_usage_t>(0xFFFFFFFFU);
+static constexpr audio_encapsulation_type_t kInvalidEncapsulationType =
+        static_cast<audio_encapsulation_type_t>(0xFFFFFFFFU);
+static constexpr audio_standard_t kInvalidAudioStandard =
+        static_cast<audio_standard_t>(0xFFFFFFFFU);
 
 TEST(HidlUtils, ConvertInvalidChannelMask) {
     AudioChannelMask invalid;
@@ -950,6 +954,53 @@
     EXPECT_TRUE(audio_port_configs_are_equal(&halConfig, &halConfigBack));
 }
 
+TEST(HidlUtils, ConvertInvalidAudioTransports) {
+    hidl_vec<AudioTransport> invalid;
+    struct audio_port_v7 halInvalid = {};
+    halInvalid.num_audio_profiles = 1;
+    halInvalid.audio_profiles[0].format = kInvalidHalFormat;
+    halInvalid.audio_profiles[0].encapsulation_type = kInvalidEncapsulationType;
+    halInvalid.num_extra_audio_descriptors = 1;
+    halInvalid.extra_audio_descriptors[0].standard = kInvalidAudioStandard;
+    halInvalid.extra_audio_descriptors[0].descriptor_length = EXTRA_AUDIO_DESCRIPTOR_SIZE + 1;
+    EXPECT_EQ(BAD_VALUE,
+              HidlUtils::audioTransportsFromHal(halInvalid, false /*isInput*/, &invalid));
+    invalid.resize(2);
+    AudioProfile invalidProfile;
+    invalidProfile.format = "random string";
+    invalid[0].audioCapability.profile(invalidProfile);
+    invalid[0].encapsulationType = "random string";
+    invalid[0].audioCapability.edid(hidl_vec<uint8_t>(EXTRA_AUDIO_DESCRIPTOR_SIZE + 1));
+    invalid[1].encapsulationType = "random string";
+    EXPECT_EQ(BAD_VALUE, HidlUtils::audioTransportsToHal(invalid, &halInvalid));
+}
+
+TEST(HidlUtils, ConvertAudioTransports) {
+    hidl_vec<AudioTransport> transports;
+    transports.resize(2);
+    AudioProfile profile;
+    profile.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
+    profile.sampleRates.resize(2);
+    profile.sampleRates[0] = 44100;
+    profile.sampleRates[1] = 48000;
+    profile.channelMasks.resize(2);
+    profile.channelMasks[0] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO);
+    profile.channelMasks[1] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
+    transports[0].audioCapability.profile(profile);
+    hidl_vec<uint8_t> shortAudioDescriptor({0x11, 0x06, 0x01});
+    transports[0].encapsulationType =
+            toString(xsd::AudioEncapsulationType::AUDIO_ENCAPSULATION_TYPE_NONE);
+    transports[1].audioCapability.edid(std::move(shortAudioDescriptor));
+    transports[1].encapsulationType =
+            toString(xsd::AudioEncapsulationType::AUDIO_ENCAPSULATION_TYPE_IEC61937);
+    struct audio_port_v7 halPort;
+    EXPECT_EQ(NO_ERROR, HidlUtils::audioTransportsToHal(transports, &halPort));
+    hidl_vec<AudioTransport> transportsBack;
+    EXPECT_EQ(NO_ERROR,
+              HidlUtils::audioTransportsFromHal(halPort, false /*isInput*/, &transportsBack));
+    EXPECT_EQ(transports, transportsBack);
+}
+
 TEST(HidlUtils, ConvertInvalidAudioPort) {
     AudioPort invalid;
     struct audio_port_v7 halInvalid = {};
@@ -958,8 +1009,10 @@
     halInvalid.num_audio_profiles = 1;
     halInvalid.audio_profiles[0].format = kInvalidHalFormat;
     EXPECT_EQ(BAD_VALUE, HidlUtils::audioPortFromHal(halInvalid, &invalid));
-    invalid.profiles.resize(1);
-    invalid.profiles[0].format = "random string";
+    invalid.transports.resize(1);
+    AudioProfile invalidProfile;
+    invalidProfile.format = "random string";
+    invalid.transports[0].audioCapability.profile(invalidProfile);
     EXPECT_EQ(BAD_VALUE, HidlUtils::audioPortToHal(invalid, &halInvalid));
 }
 
@@ -967,14 +1020,22 @@
     AudioPort port = {};
     port.id = 42;
     port.name = "test";
-    port.profiles.resize(1);
-    port.profiles[0].format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
-    port.profiles[0].sampleRates.resize(2);
-    port.profiles[0].sampleRates[0] = 44100;
-    port.profiles[0].sampleRates[1] = 48000;
-    port.profiles[0].channelMasks.resize(2);
-    port.profiles[0].channelMasks[0] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO);
-    port.profiles[0].channelMasks[1] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
+    port.transports.resize(2);
+    AudioProfile profile;
+    profile.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
+    profile.sampleRates.resize(2);
+    profile.sampleRates[0] = 44100;
+    profile.sampleRates[1] = 48000;
+    profile.channelMasks.resize(2);
+    profile.channelMasks[0] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_MONO);
+    profile.channelMasks[1] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
+    port.transports[0].audioCapability.profile(profile);
+    port.transports[0].encapsulationType =
+            toString(xsd::AudioEncapsulationType::AUDIO_ENCAPSULATION_TYPE_NONE);
+    hidl_vec<uint8_t> shortAudioDescriptor({0x11, 0x06, 0x01});
+    port.transports[1].audioCapability.edid(std::move(shortAudioDescriptor));
+    port.transports[1].encapsulationType =
+            toString(xsd::AudioEncapsulationType::AUDIO_ENCAPSULATION_TYPE_IEC61937);
     port.gains.resize(1);
     port.gains[0].channelMask = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO);
     port.ext.device({});
diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
index 657b42d..0b3098b 100644
--- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -580,12 +580,19 @@
         // Starting / resuming of streams is asynchronous at HAL level.
         // Sometimes HAL doesn't have enough information until the audio data actually gets
         // consumed by the hardware.
-        do {
+        bool timedOut = false;
+        res = Result::INVALID_STATE;
+        for (android::base::Timer elapsed;
+             res != Result::OK && !writer.hasError() &&
+             !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
+            usleep(kWriteDurationUs);
             ASSERT_OK(stream->getPresentationPosition(returnIn(res, framesInitial, ts)));
             ASSERT_RESULT(okOrInvalidState, res);
-        } while (res != Result::OK);
+        }
+        ASSERT_FALSE(writer.hasError());
+        ASSERT_FALSE(timedOut);
+
         uint64_t frames = framesInitial;
-        bool timedOut = false;
         for (android::base::Timer elapsed;
              frames <= framesInitial && !writer.hasError() &&
              !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
@@ -666,11 +673,18 @@
                 allParams.begin(), allParams.end(), std::back_inserter(pcmParams), [](auto cfg) {
                     const auto& flags = std::get<PARAM_FLAGS>(cfg);
                     return xsd::isLinearPcm(std::get<PARAM_CONFIG>(cfg).base.format)
-                           // MMAP NOIRQ profiles use different reading protocol.
+                           // MMAP NOIRQ profiles use different reading protocol,
+                           // reading h/w hotword might require Soundtrigger to be active.
                            &&
-                           std::find(flags.begin(), flags.end(),
-                                     toString(xsd::AudioInOutFlag::AUDIO_INPUT_FLAG_MMAP_NOIRQ)) ==
-                                   flags.end() &&
+                           std::find_if(
+                                   flags.begin(), flags.end(),
+                                   [](const auto& flag) {
+                                       return flag == toString(
+                                                              xsd::AudioInOutFlag::
+                                                                      AUDIO_INPUT_FLAG_MMAP_NOIRQ) ||
+                                              flag == toString(xsd::AudioInOutFlag::
+                                                                       AUDIO_INPUT_FLAG_HW_HOTWORD);
+                                   }) == flags.end() &&
                            !getCachedPolicyConfig()
                                     .getAttachedSourceDeviceForMixPort(
                                             std::get<PARAM_DEVICE_NAME>(
@@ -690,6 +704,15 @@
         InputStreamTest::TearDown();
     }
 
+    bool canQueryCapturePosition() const {
+        auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort(
+                getDeviceName(), getMixPortName());
+        // Returning 'true' when no source is found so the test can fail later with a more clear
+        // problem description.
+        return !maybeSourceAddress.has_value() ||
+               !xsd::isTelephonyDevice(maybeSourceAddress.value().deviceType);
+    }
+
     void createPatchIfNeeded() {
         auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort(
                 getDeviceName(), getMixPortName());
@@ -714,6 +737,7 @@
             EXPECT_OK(stream->setDevices({maybeSourceAddress.value()}));
         }
     }
+
     void releasePatchIfNeeded() {
         if (areAudioPatchesSupported()) {
             if (mHasPatch) {
@@ -724,7 +748,42 @@
             EXPECT_OK(stream->setDevices({address}));
         }
     }
-    const std::string& getMixPortName() const { return std::get<PARAM_PORT_NAME>(GetParam()); }
+
+    void waitForCapturePositionAdvance(StreamReader& reader, uint64_t* firstPosition = nullptr,
+                                       uint64_t* lastPosition = nullptr) {
+        static constexpr int kReadDurationUs = 50 * 1000;
+        static constexpr std::chrono::milliseconds kPositionChangeTimeout{10000};
+        uint64_t framesInitial, ts;
+        // Starting / resuming of streams is asynchronous at HAL level.
+        // Sometimes HAL doesn't have enough information until the audio data actually has been
+        // produced by the hardware. Legacy HALs might return NOT_SUPPORTED when they actually
+        // mean INVALID_STATE.
+        bool timedOut = false;
+        res = Result::INVALID_STATE;
+        for (android::base::Timer elapsed;
+             res != Result::OK && !reader.hasError() &&
+             !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
+            usleep(kReadDurationUs);
+            ASSERT_OK(stream->getCapturePosition(returnIn(res, framesInitial, ts)));
+            ASSERT_RESULT(okOrInvalidStateOrNotSupported, res);
+        }
+        ASSERT_FALSE(reader.hasError());
+        ASSERT_FALSE(timedOut);
+
+        uint64_t frames = framesInitial;
+        for (android::base::Timer elapsed;
+             frames <= framesInitial && !reader.hasError() &&
+             !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
+            usleep(kReadDurationUs);
+            ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, ts)));
+            ASSERT_RESULT(Result::OK, res);
+        }
+        EXPECT_FALSE(timedOut);
+        EXPECT_FALSE(reader.hasError());
+        EXPECT_GT(frames, framesInitial);
+        if (firstPosition) *firstPosition = framesInitial;
+        if (lastPosition) *lastPosition = frames;
+    }
 
   private:
     AudioPatchHandle mPatchHandle = {};
@@ -740,47 +799,36 @@
 
 TEST_P(PcmOnlyConfigInputStreamTest, CapturePositionAdvancesWithReads) {
     doc::test("Check that the capture position advances with reads");
+    if (!canQueryCapturePosition()) {
+        GTEST_SKIP() << "Capture position retrieval is not possible";
+    }
 
     ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded());
     StreamReader reader(stream.get(), stream->getBufferSize());
     ASSERT_TRUE(reader.start());
     EXPECT_TRUE(reader.waitForAtLeastOneCycle());
-
-    uint64_t framesInitial, ts;
-    ASSERT_OK(stream->getCapturePosition(returnIn(res, framesInitial, ts)));
-    ASSERT_RESULT(Result::OK, res);
-
-    EXPECT_TRUE(reader.waitForAtLeastOneCycle());
-
-    uint64_t frames;
-    ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, ts)));
-    ASSERT_RESULT(Result::OK, res);
-    EXPECT_GT(frames, framesInitial);
-
-    reader.stop();
-    releasePatchIfNeeded();
+    ASSERT_NO_FATAL_FAILURE(waitForCapturePositionAdvance(reader));
 }
 
 TEST_P(PcmOnlyConfigInputStreamTest, CapturePositionPreservedOnStandby) {
     doc::test("Check that the capture position does not reset on standby");
+    if (!canQueryCapturePosition()) {
+        GTEST_SKIP() << "Capture position retrieval is not possible";
+    }
 
     ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded());
     StreamReader reader(stream.get(), stream->getBufferSize());
     ASSERT_TRUE(reader.start());
     EXPECT_TRUE(reader.waitForAtLeastOneCycle());
 
-    uint64_t framesInitial, ts;
-    ASSERT_OK(stream->getCapturePosition(returnIn(res, framesInitial, ts)));
-    ASSERT_RESULT(Result::OK, res);
-
+    uint64_t framesInitial;
+    ASSERT_NO_FATAL_FAILURE(waitForCapturePositionAdvance(reader, nullptr, &framesInitial));
     reader.pause();
     ASSERT_OK(stream->standby());
     reader.resume();
-    EXPECT_FALSE(reader.hasError());
 
     uint64_t frames;
-    ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, ts)));
-    ASSERT_RESULT(Result::OK, res);
+    ASSERT_NO_FATAL_FAILURE(waitForCapturePositionAdvance(reader, &frames, nullptr));
     EXPECT_GT(frames, framesInitial);
 
     reader.stop();
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index ae1467d..aa7fd8e 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -1194,7 +1194,17 @@
 #if MAJOR_VERSION <= 6
         address.device = AudioDevice::IN_DEFAULT;
 #elif MAJOR_VERSION >= 7
-        address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT);
+        auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort(
+                getDeviceName(), getMixPortName());
+        if (maybeSourceAddress.has_value() &&
+            !xsd::isTelephonyDevice(maybeSourceAddress.value().deviceType)) {
+            address = maybeSourceAddress.value();
+            auto& metadata = initMetadata.tracks[0];
+            metadata.source = toString(xsd::AudioSource::AUDIO_SOURCE_UNPROCESSED);
+            metadata.channelMask = getConfig().base.channelMask;
+        } else {
+            address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT);
+        }
 #endif
         const AudioConfig& config = getConfig();
         auto flags = getInputFlags();
@@ -1212,7 +1222,8 @@
 #elif MAJOR_VERSION >= 4 && MAJOR_VERSION <= 6
      const SinkMetadata initMetadata = {{ {.source = AudioSource::DEFAULT, .gain = 1 } }};
 #elif MAJOR_VERSION >= 7
-     const SinkMetadata initMetadata = {
+     const std::string& getMixPortName() const { return std::get<PARAM_PORT_NAME>(GetParam()); }
+     SinkMetadata initMetadata = {
              {{.source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT),
                .gain = 1,
                .tags = {},
diff --git a/audio/core/all-versions/vts/functional/tests/streamworker_tests.cpp b/audio/core/all-versions/vts/functional/tests/streamworker_tests.cpp
index 75116af..925fd33 100644
--- a/audio/core/all-versions/vts/functional/tests/streamworker_tests.cpp
+++ b/audio/core/all-versions/vts/functional/tests/streamworker_tests.cpp
@@ -33,12 +33,6 @@
     // Use nullptr to test error reporting from the worker thread.
     explicit TestWorker(TestStream* stream) : mStream(stream) {}
 
-    void ensureWorkerCycled() {
-        const size_t cyclesBefore = mWorkerCycles;
-        while (mWorkerCycles == cyclesBefore && !hasError()) {
-            sched_yield();
-        }
-    }
     size_t getWorkerCycles() const { return mWorkerCycles; }
     bool hasWorkerCycleCalled() const { return mWorkerCycles != 0; }
     bool hasNoWorkerCycleCalled(useconds_t usec) {
@@ -131,21 +125,21 @@
 
 TEST_P(StreamWorkerTest, Start) {
     ASSERT_TRUE(worker.start());
-    worker.ensureWorkerCycled();
+    worker.waitForAtLeastOneCycle();
     EXPECT_FALSE(worker.hasError());
 }
 
 TEST_P(StreamWorkerTest, WorkerError) {
     ASSERT_TRUE(worker.start());
     stream.error = true;
-    worker.ensureWorkerCycled();
+    worker.waitForAtLeastOneCycle();
     EXPECT_TRUE(worker.hasError());
     EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
 }
 
 TEST_P(StreamWorkerTest, PauseResume) {
     ASSERT_TRUE(worker.start());
-    worker.ensureWorkerCycled();
+    worker.waitForAtLeastOneCycle();
     EXPECT_FALSE(worker.hasError());
     worker.pause();
     EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
@@ -159,7 +153,7 @@
 
 TEST_P(StreamWorkerTest, StopPaused) {
     ASSERT_TRUE(worker.start());
-    worker.ensureWorkerCycled();
+    worker.waitForAtLeastOneCycle();
     EXPECT_FALSE(worker.hasError());
     worker.pause();
     worker.stop();
@@ -169,7 +163,7 @@
 TEST_P(StreamWorkerTest, PauseAfterErrorIgnored) {
     ASSERT_TRUE(worker.start());
     stream.error = true;
-    worker.ensureWorkerCycled();
+    worker.waitForAtLeastOneCycle();
     EXPECT_TRUE(worker.hasError());
     worker.pause();
     EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
@@ -179,7 +173,7 @@
 TEST_P(StreamWorkerTest, ResumeAfterErrorIgnored) {
     ASSERT_TRUE(worker.start());
     stream.error = true;
-    worker.ensureWorkerCycled();
+    worker.waitForAtLeastOneCycle();
     EXPECT_TRUE(worker.hasError());
     worker.resume();
     EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
@@ -188,14 +182,14 @@
 
 TEST_P(StreamWorkerTest, WorkerErrorOnResume) {
     ASSERT_TRUE(worker.start());
-    worker.ensureWorkerCycled();
+    worker.waitForAtLeastOneCycle();
     EXPECT_FALSE(worker.hasError());
     worker.pause();
     EXPECT_FALSE(worker.hasError());
     stream.error = true;
     EXPECT_FALSE(worker.hasError());
     worker.resume();
-    worker.ensureWorkerCycled();
+    worker.waitForAtLeastOneCycle();
     EXPECT_TRUE(worker.hasError());
     EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
 }
diff --git a/audio/effect/all-versions/default/util/EffectUtils.cpp b/audio/effect/all-versions/default/util/EffectUtils.cpp
index b4382dc..1156d21 100644
--- a/audio/effect/all-versions/default/util/EffectUtils.cpp
+++ b/audio/effect/all-versions/default/util/EffectUtils.cpp
@@ -25,8 +25,6 @@
 
 #include "util/EffectUtils.h"
 
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
-
 using ::android::hardware::audio::common::CPP_VERSION::implementation::HidlUtils;
 using ::android::hardware::audio::common::CPP_VERSION::implementation::UuidUtils;
 using ::android::hardware::audio::common::utils::EnumBitfield;
@@ -154,6 +152,29 @@
     return result;
 }
 
+template <std::size_t N>
+inline hidl_string charBufferFromHal(const char (&halBuf)[N]) {
+    // Even if the original field contains a non-terminated string, hidl_string
+    // adds a NUL terminator.
+    return hidl_string(halBuf, strnlen(halBuf, N));
+}
+
+template <std::size_t N>
+inline status_t charBufferToHal(const hidl_string& str, char (&halBuf)[N], const char* fieldName) {
+    static_assert(N > 0);
+    const size_t halBufChars = N - 1;  // Reserve one character for terminating NUL.
+    status_t result = NO_ERROR;
+    size_t strSize = str.size();
+    if (strSize > halBufChars) {
+        ALOGE("%s is too long: %zu (%zu max)", fieldName, strSize, halBufChars);
+        strSize = halBufChars;
+        result = BAD_VALUE;
+    }
+    strncpy(halBuf, str.c_str(), strSize);
+    halBuf[strSize] = '\0';
+    return result;
+}
+
 status_t EffectUtils::effectDescriptorFromHal(const effect_descriptor_t& halDescriptor,
                                               EffectDescriptor* descriptor) {
     UuidUtils::uuidFromHal(halDescriptor.type, &descriptor->type);
@@ -166,9 +187,8 @@
     memcpy(descriptor->implementor.data(), halDescriptor.implementor,
            descriptor->implementor.size());
 #else
-    descriptor->name = hidl_string(halDescriptor.name, ARRAY_SIZE(halDescriptor.name));
-    descriptor->implementor =
-            hidl_string(halDescriptor.implementor, ARRAY_SIZE(halDescriptor.implementor));
+    descriptor->name = charBufferFromHal(halDescriptor.name);
+    descriptor->implementor = charBufferFromHal(halDescriptor.implementor);
 #endif
     return NO_ERROR;
 }
@@ -186,25 +206,11 @@
     memcpy(halDescriptor->implementor, descriptor.implementor.data(),
            descriptor.implementor.size());
 #else
-    // According to 'dumpEffectDescriptor' 'name' and 'implementor' must be NUL-terminated.
-    size_t nameSize = descriptor.name.size();
-    if (nameSize >= ARRAY_SIZE(halDescriptor->name)) {
-        ALOGE("effect name is too long: %zu (%zu max)", nameSize,
-              ARRAY_SIZE(halDescriptor->name) - 1);
-        nameSize = ARRAY_SIZE(halDescriptor->name) - 1;
-        result = BAD_VALUE;
-    }
-    strncpy(halDescriptor->name, descriptor.name.c_str(), nameSize);
-    halDescriptor->name[nameSize] = '\0';
-    size_t implementorSize = descriptor.implementor.size();
-    if (implementorSize >= ARRAY_SIZE(halDescriptor->implementor)) {
-        ALOGE("effect implementor is too long: %zu (%zu max)", implementorSize,
-              ARRAY_SIZE(halDescriptor->implementor) - 1);
-        implementorSize = ARRAY_SIZE(halDescriptor->implementor) - 1;
-        result = BAD_VALUE;
-    }
-    strncpy(halDescriptor->implementor, descriptor.implementor.c_str(), implementorSize);
-    halDescriptor->implementor[implementorSize] = '\0';
+    // According to 'dumpEffectDescriptor', 'name' and 'implementor' must be NUL-terminated.
+    CONVERT_CHECKED(charBufferToHal(descriptor.name, halDescriptor->name, "effect name"), result);
+    CONVERT_CHECKED(charBufferToHal(descriptor.implementor, halDescriptor->implementor,
+                                    "effect implementor"),
+                    result);
 #endif
     return result;
 }
diff --git a/audio/effect/all-versions/default/util/tests/effectutils_tests.cpp b/audio/effect/all-versions/default/util/tests/effectutils_tests.cpp
index f3651de..d021fa0 100644
--- a/audio/effect/all-versions/default/util/tests/effectutils_tests.cpp
+++ b/audio/effect/all-versions/default/util/tests/effectutils_tests.cpp
@@ -154,3 +154,20 @@
     EXPECT_EQ(NO_ERROR, EffectUtils::effectDescriptorFromHal(halDesc, &descBack));
     EXPECT_EQ(desc, descBack);
 }
+
+TEST(EffectUtils, ConvertNameAndImplementor) {
+    for (size_t i = 0; i < EFFECT_STRING_LEN_MAX; ++i) {
+        effect_descriptor_t halDesc{};
+        for (size_t c = 0; c < i; ++c) {  // '<' to accommodate NUL terminator.
+            halDesc.name[c] = halDesc.implementor[c] = 'A' + static_cast<char>(c);
+        }
+        EffectDescriptor desc;
+        EXPECT_EQ(NO_ERROR, EffectUtils::effectDescriptorFromHal(halDesc, &desc));
+        effect_descriptor_t halDescBack;
+        EXPECT_EQ(NO_ERROR, EffectUtils::effectDescriptorToHal(desc, &halDescBack));
+        EXPECT_EQ(i, strlen(halDescBack.name));
+        EXPECT_EQ(i, strlen(halDescBack.implementor));
+        EXPECT_EQ(0, strcmp(halDesc.name, halDescBack.name));
+        EXPECT_EQ(0, strcmp(halDesc.implementor, halDescBack.implementor));
+    }
+}
diff --git a/keymaster/4.1/default/Android.bp b/keymaster/4.1/default/Android.bp
index 3e2289a..6ec1fae 100644
--- a/keymaster/4.1/default/Android.bp
+++ b/keymaster/4.1/default/Android.bp
@@ -45,5 +45,14 @@
         "liblog",
         "libutils",
     ],
+    required: [
+        "android.hardware.hardware_keystore.km41.xml",
+    ],
+}
 
+prebuilt_etc {
+    name: "android.hardware.hardware_keystore.km41.xml",
+    sub_dir: "permissions",
+    vendor: true,
+    src: "android.hardware.hardware_keystore.km41.xml",
 }
diff --git a/keymaster/4.1/default/android.hardware.hardware_keystore.km41.xml b/keymaster/4.1/default/android.hardware.hardware_keystore.km41.xml
new file mode 100644
index 0000000..0dbeed8
--- /dev/null
+++ b/keymaster/4.1/default/android.hardware.hardware_keystore.km41.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<permissions>
+  <feature name="android.hardware.hardware_keystore" version="41" />
+</permissions>
diff --git a/power/stats/aidl/Android.bp b/power/stats/aidl/Android.bp
index 454c69a..0dbf9b4 100644
--- a/power/stats/aidl/Android.bp
+++ b/power/stats/aidl/Android.bp
@@ -41,4 +41,5 @@
             enabled: true,
         },
     },
+    host_supported: true,
 }
diff --git a/radio/1.6/IRadio.hal b/radio/1.6/IRadio.hal
index d201332..a4e8811 100644
--- a/radio/1.6/IRadio.hal
+++ b/radio/1.6/IRadio.hal
@@ -544,4 +544,43 @@
      * as the input param.
      */
     oneway setCarrierInfoForImsiEncryption_1_6(int32_t serial, @1.6::ImsiEncryptionInfo imsiEncryptionInfo);
+
+    /**
+     * Get the local and global phonebook records from the SIM card.
+     * This should be called again after a simPhonebookChanged notification is received.
+     *
+     * The phonebook records are received via IRadioIndication.simPhonebookRecordsReceived()
+     *
+     * @param serial Serial number of request.
+     *
+     * Response callback is IRadioResponse.getSimPhonebookRecordsResponse()
+     */
+    oneway getSimPhonebookRecords(int32_t serial);
+
+    /**
+     * Get the phone book capacity
+     *
+     * @param serial Serial number of request.
+     *
+     * Response function is defined from IRadioResponse.getSimPhonebookCapacityResponse()
+     */
+    oneway getSimPhonebookCapacity(int32_t serial);
+
+    /**
+     * Insert, delete or update a phonebook record on the SIM card.
+     * If the index of recordInfo is 0, the phonebook record will be added to global or
+     * local phonebook, and global phonebook has higher priority than local phonebook.
+     *
+     * If the fields in the recordInfo are all empty except for the index, the phonebook
+     * record specified by the index will be deleted.
+     *
+     * The indication simPhonebookChanged will be called after every successful call of
+     * updateSimPhonebookRecords.
+     *
+     * @param serial Serial number of request.
+     * @param recordInfo Details of the record to insert, delete or update.
+     *
+     * Response callback is IRadioResponse.updateSimPhonebookRecordsResponse()
+     */
+    oneway updateSimPhonebookRecords(int32_t serial, PhonebookRecordInfo recordInfo);
 };
diff --git a/radio/1.6/IRadioIndication.hal b/radio/1.6/IRadioIndication.hal
index a53d7c1..9788345 100644
--- a/radio/1.6/IRadioIndication.hal
+++ b/radio/1.6/IRadioIndication.hal
@@ -23,7 +23,9 @@
 import @1.6::NetworkScanResult;
 import @1.6::SignalStrength;
 import @1.6::SetupDataCallResult;
+import @1.6::PbReceivedStatus;
 import @1.6::PhysicalChannelConfig;
+import @1.6::PhonebookRecordInfo;
 
 /**
  * Interface declaring unsolicited radio indications.
@@ -72,7 +74,6 @@
      */
     oneway currentLinkCapacityEstimate_1_6(RadioIndicationType type, LinkCapacityEstimate lce);
 
-
     /**
      * Indicates current signal strength of the radio.
      *
@@ -113,4 +114,27 @@
      */
     oneway currentPhysicalChannelConfigs_1_6(RadioIndicationType type,
             vec<PhysicalChannelConfig> configs);
+
+    /**
+     * Indicates whether SIM phonebook is changed.
+     *
+     * This indication is sent whenever the SIM phonebook is changed, including SIM is
+     * inserted or removed and updated by IRadio.updateSimPhonebookRecords.
+     *
+     * @param type Type of radio indication
+     */
+    oneway simPhonebookChanged(RadioIndicationType type);
+
+    /**
+     * Indicates the content of all the used records in the SIM phonebook.
+     *
+     * This indication is associated with the API getSimPhonebookRecords and
+     * might be received more than once that is replying on the record count.
+     *
+     * @param type Type of radio indication
+     * @param status Status of PbReceivedStatus
+     * @param records Vector of PhonebookRecordInfo
+     */
+    oneway simPhonebookRecordsReceived(RadioIndicationType type,
+            PbReceivedStatus status, vec<PhonebookRecordInfo> records);
 };
diff --git a/radio/1.6/IRadioResponse.hal b/radio/1.6/IRadioResponse.hal
index 883711c..f2c06b7 100644
--- a/radio/1.6/IRadioResponse.hal
+++ b/radio/1.6/IRadioResponse.hal
@@ -27,6 +27,7 @@
 import @1.6::SetupDataCallResult;
 import @1.6::SignalStrength;
 import @1.6::SlicingConfig;
+import @1.6::PhonebookCapacity;
 
 /**
  * Interface declaring response functions to solicited radio requests.
@@ -436,4 +437,57 @@
      */
     oneway getSlicingConfigResponse(RadioResponseInfo info,
             SlicingConfig slicingConfig);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:INVALID_SIM_STATE
+     *   RadioError:MODEM_ERR
+     *   RadioError:INTERNAL_ERR
+     * REQUEST_NOT_SUPPORTED may only be returned on devices that don't support this API,
+     * indicated by the HAL capability CAPABILITY_SIM_PHONEBOOK_IN_MODEM.
+     */
+    oneway getSimPhonebookRecordsResponse(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param capacity Response capacity enum indicating response processing status
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:INVALID_SIM_STATE
+     *   RadioError:MODEM_ERR
+     *   RadioError:INTERNAL_ERR
+     * REQUEST_NOT_SUPPORTED may only be returned on devices that don't support this API,
+     * indicated by the HAL capability CAPABILITY_SIM_PHONEBOOK_IN_MODEM.
+     */
+    oneway getSimPhonebookCapacityResponse(RadioResponseInfo info, PhonebookCapacity capacity);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param updatedRecordIndex The index of the updated or inserted record in the phonebook and
+     *                           the minimum value is 1
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:INVALID_SIM_STATE
+     *   RadioError:MODEM_ERR
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:SIM_ERR
+     *   RadioError:NO_SUCH_ENTRY
+     *   RadioError:NO_RESOURCES
+     * REQUEST_NOT_SUPPORTED may only be returned on devices that don't support this API,
+     * indicated by the HAL capability CAPABILITY_SIM_PHONEBOOK_IN_MODEM.
+     */
+    oneway updateSimPhonebookRecordsResponse(RadioResponseInfo info, int32_t updatedRecordIndex);
 };
diff --git a/radio/1.6/types.hal b/radio/1.6/types.hal
index c7564ce..82c9daa 100644
--- a/radio/1.6/types.hal
+++ b/radio/1.6/types.hal
@@ -1104,3 +1104,106 @@
     @1.1::ImsiEncryptionInfo base;
     PublicKeyType keyType;         // Public key type
 };
+
+/**
+ * Phonebook-record-information specified by EF_ADN(Abbreviated dialing numbers)
+ * record of SIM as per 3GPP spec 31.102 v15 Section-4.4.2.3.
+ */
+struct PhonebookRecordInfo {
+    /** Record index. 0 is used to insert a record */
+    uint32_t recordId;
+
+    /** Alpha identifier, empty string if no value */
+    string name;
+
+    /** Dialling number, empty string if no value */
+    string number;
+
+    /** Email addresses */
+    vec<string> emails;
+
+    /** Additional numbers */
+    vec<string> additionalNumbers;
+};
+
+struct PhonebookCapacity {
+    /**
+     * Maximum number of ADN records possible in the SIM phonebook
+     * Needs to be non-negative
+     */
+    int32_t maxAdnRecords;
+
+    /**
+     * Used ADN records in the SIM phonebook
+     * Needs to be non-negative
+     */
+    int32_t usedAdnRecords;
+
+    /**
+     * Maximum email records possible in the SIM phonebook
+     * Needs to be non-negative
+     */
+    int32_t maxEmailRecords;
+
+    /**
+     * Used email records in the SIM phonebook
+     * Needs to be non-negative
+     */
+    int32_t usedEmailRecords;
+
+    /**
+     * Maximum additional number records possible in the SIM phonebook
+     * Needs to be non-negative
+     */
+    int32_t maxAdditionalNumberRecords;
+
+    /**
+     * Used additional number records in the SIM phonebook
+     * Needs to be non-negative
+     */
+    int32_t usedAdditionalNumberRecords;
+
+    /**
+     * Maximum name length possible in the SIM phonebook
+     * Needs to be non-negative
+     */
+    int32_t maxNameLen;
+
+    /**
+     * Maximum number length possible in the SIM phonebook
+     * Needs to be non-negative
+     */
+    int32_t maxNumberLen;
+
+    /**
+     * Maximum email length possible in the SIM phonebook
+     * Needs to be non-negative
+     */
+    int32_t maxEmailLen;
+
+    /**
+     * Maximum additional number length possible in the SIM phonebook
+     * Needs to be non-negative
+     */
+    int32_t maxAdditionalNumberLen;
+};
+
+/**
+ * Enum representing the status of the received PB indication,
+ * PB_RECEIVED_OK indicates this retrieval is fine
+ * PB_RECEIVED_ERROR indicates one error happens, in general, the process
+ *   can't be restored soon.
+ * PB_RECEIVED_ABORT indicates the process is interrupted, in this case,
+ *   modem might need resources and interrupt the current process, or it is
+ *   timed out to receive all indications, and client can retry soon.
+ * PB_RECEIVED_FINAL indicates the whole process is finished with a full
+ *   chunk of phonebook data, means this is a last indication with the left
+ *   data.
+ */
+enum PbReceivedStatus : int32_t {
+    PB_RECEIVED_OK = 1,
+    PB_RECEIVED_ERROR = 2,
+    PB_RECEIVED_ABORT = 3,
+    PB_RECEIVED_FINAL = 4,
+};
+
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 7fde18e..a9c21ff 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
@@ -727,8 +727,8 @@
 
     radio_v1_6->setCarrierInfoForImsiEncryption_1_6(serial, imsiInfo);
     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(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo_v1_0.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo_v1_0.serial);
 
     if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(
@@ -737,3 +737,141 @@
                  ::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
     }
 }
+
+/*
+ * Test IRadio.getSimPhonebookRecords() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_6, getSimPhonebookRecords) {
+    serial = GetRandomSerialNumber();
+    radio_v1_6->getSimPhonebookRecords(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 (cardStatus.base.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_v1_6->rspInfo.error,
+            {::android::hardware::radio::V1_6::RadioError::INVALID_SIM_STATE,
+             ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+             ::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
+             ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+             ::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED},
+             CHECK_GENERAL_ERROR));
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
+        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));
+    }
+}
+
+/*
+ * Test IRadio.getSimPhonebookCapacity for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, getSimPhonebookCapacity) {
+    serial = GetRandomSerialNumber();
+    radio_v1_6->getSimPhonebookCapacity(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 (cardStatus.base.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_v1_6->rspInfo.error,
+            {::android::hardware::radio::V1_6::RadioError::INVALID_SIM_STATE,
+             ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+             ::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
+             ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+             ::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED},
+             CHECK_GENERAL_ERROR));
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
+        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));
+
+        ::android::hardware::radio::V1_6::PhonebookCapacity pbCapacity =
+             radioRsp_v1_6->capacity;
+        if(pbCapacity.maxAdnRecords > 0) {
+            EXPECT_TRUE(pbCapacity.maxNameLen > 0 && pbCapacity.maxNumberLen > 0);
+            EXPECT_TRUE(pbCapacity.usedAdnRecords <= pbCapacity.maxAdnRecords);
+        }
+
+        if(pbCapacity.maxEmailRecords > 0) {
+            EXPECT_TRUE(pbCapacity.maxEmailLen > 0);
+            EXPECT_TRUE(pbCapacity.usedEmailRecords <= pbCapacity.maxEmailRecords);
+        }
+
+        if(pbCapacity.maxAdditionalNumberRecords > 0) {
+            EXPECT_TRUE(pbCapacity.maxAdditionalNumberLen > 0);
+            EXPECT_TRUE(pbCapacity.usedAdditionalNumberRecords <= pbCapacity.maxAdditionalNumberRecords);
+        }
+    }
+}
+
+/*
+ * Test IRadio.updateSimPhonebookRecords() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_6, updateSimPhonebookRecords) {
+    serial = GetRandomSerialNumber();
+    radio_v1_6->getSimPhonebookCapacity(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 (cardStatus.base.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_v1_6->rspInfo.error,
+            {::android::hardware::radio::V1_6::RadioError::INVALID_SIM_STATE,
+             ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+             ::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
+             ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+             ::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED},
+             CHECK_GENERAL_ERROR));
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
+        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));
+        ::android::hardware::radio::V1_6::PhonebookCapacity pbCapacity =
+                radioRsp_v1_6->capacity;
+
+        serial = GetRandomSerialNumber();
+        radio_v1_6->getSimPhonebookRecords(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);
+        EXPECT_EQ(::android::hardware::radio::V1_6::RadioError::NONE, radioRsp_v1_6->rspInfo.error);
+
+        if(pbCapacity.maxAdnRecords > 0
+                && pbCapacity.usedAdnRecords < pbCapacity.maxAdnRecords) {
+            // Add a phonebook record
+            PhonebookRecordInfo recordInfo;
+            recordInfo.recordId = 0;
+            recordInfo.name = "ABC";
+            recordInfo.number = "1234567890";
+            serial = GetRandomSerialNumber();
+            radio_v1_6->updateSimPhonebookRecords(serial, recordInfo);
+
+            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);
+            int index = radioRsp_v1_6->updatedRecordIndex;
+            EXPECT_TRUE(index > 0);
+
+            // Deleted a phonebook record
+            recordInfo.recordId = index;
+            recordInfo.name = "";
+            recordInfo.number = "";
+            serial = GetRandomSerialNumber();
+            radio_v1_6->updateSimPhonebookRecords(serial, recordInfo);
+
+            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);
+        }
+    }
+}
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h b/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
index 23378b5..4fc17e5 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
+++ b/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
@@ -103,6 +103,11 @@
     ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo> barringInfos;
 
     RadioResponse_v1_6(RadioResponseWaiter& parent_v1_6);
+
+    // Phone Book
+    ::android::hardware::radio::V1_6::PhonebookCapacity capacity;
+    int32_t updatedRecordIndex;
+
     virtual ~RadioResponse_v1_6() = default;
 
     Return<void> getIccCardStatusResponse(
@@ -829,6 +834,17 @@
     Return<void> getSlicingConfigResponse(
             const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
             const ::android::hardware::radio::V1_6::SlicingConfig& slicingConfig);
+
+    Return<void> getSimPhonebookRecordsResponse(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
+
+    Return<void> getSimPhonebookCapacityResponse(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_6::PhonebookCapacity& capacity);
+
+    Return<void> updateSimPhonebookRecordsResponse(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+            int32_t updatedRecordIndex);
 };
 
 /* Callback class for radio indication */
@@ -1073,6 +1089,14 @@
             const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/,
             const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo>&
             /*barringInfos*/);
+
+    Return<void> simPhonebookChanged(RadioIndicationType type);
+
+    Return<void> simPhonebookRecordsReceived(
+            RadioIndicationType type,
+            ::android::hardware::radio::V1_6::PbReceivedStatus status,
+            const ::android::hardware::hidl_vec<::android::hardware::radio::V1_6::PhonebookRecordInfo>&
+                    records);
 };
 
 // The main test class for Radio HIDL.
diff --git a/radio/1.6/vts/functional/radio_indication.cpp b/radio/1.6/vts/functional/radio_indication.cpp
index e7a9680..8292131 100644
--- a/radio/1.6/vts/functional/radio_indication.cpp
+++ b/radio/1.6/vts/functional/radio_indication.cpp
@@ -412,3 +412,16 @@
                 ::android::hardware::radio::V1_6::CellInfo>& /*records*/) {
     return Void();
 }
+
+Return<void> RadioIndication_v1_6::simPhonebookChanged(
+        RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_6::simPhonebookRecordsReceived(
+        RadioIndicationType /*type*/,
+        ::android::hardware::radio::V1_6::PbReceivedStatus /*status*/,
+        const ::android::hardware::hidl_vec<
+        ::android::hardware::radio::V1_6::PhonebookRecordInfo>& /*records*/) {
+    return Void();
+}
diff --git a/radio/1.6/vts/functional/radio_response.cpp b/radio/1.6/vts/functional/radio_response.cpp
index d0c2984..2b6d1bb 100644
--- a/radio/1.6/vts/functional/radio_response.cpp
+++ b/radio/1.6/vts/functional/radio_response.cpp
@@ -87,7 +87,9 @@
 }
 
 Return<void> RadioResponse_v1_6::hangupConnectionResponse(
-        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& info) {
+    rspInfo_v1_0 = info;
+    parent_v1_6.notify(info.serial);
     return Void();
 }
 
@@ -749,7 +751,9 @@
 
 /* 1.1 Apis */
 Return<void> RadioResponse_v1_6::setCarrierInfoForImsiEncryptionResponse(
-        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& info) {
+    rspInfo_v1_0 = info;
+    parent_v1_6.notify(info.serial);
     return Void();
 }
 
@@ -1232,3 +1236,28 @@
     parent_v1_6.notify(info.serial);
     return Void();
 }
+
+Return<void> RadioResponse_v1_6::getSimPhonebookRecordsResponse(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_6::getSimPhonebookCapacityResponse(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_6::PhonebookCapacity& capacity) {
+    rspInfo = info;
+    this->capacity = capacity;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_6::updateSimPhonebookRecordsResponse(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+        int32_t updatedRecordIndex) {
+    rspInfo = info;
+    this->updatedRecordIndex = updatedRecordIndex;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
diff --git a/security/keymint/aidl/OWNERS b/security/keymint/aidl/OWNERS
index 5c79db8..a93b171 100644
--- a/security/keymint/aidl/OWNERS
+++ b/security/keymint/aidl/OWNERS
@@ -1,3 +1,4 @@
+jbires@google.com
 jdanis@google.com
 seleneh@google.com
 swillden@google.com
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/DeviceInfo.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/DeviceInfo.aidl
new file mode 100644
index 0000000..d04d49c
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/DeviceInfo.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+/* @hide */
+@VintfStability
+parcelable DeviceInfo {
+  byte[] deviceInfo;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
index 195590c..4f6fb28 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -47,6 +47,7 @@
   android.hardware.security.keymint.BeginResult begin(in android.hardware.security.keymint.KeyPurpose purpose, in byte[] keyBlob, in android.hardware.security.keymint.KeyParameter[] params, in android.hardware.security.keymint.HardwareAuthToken authToken);
   void deviceLocked(in boolean passwordOnly, in @nullable android.hardware.security.secureclock.TimeStampToken timestampToken);
   void earlyBootEnded();
+  byte[] convertStorageKeyToEphemeral(in byte[] storageKeyBlob);
   byte[] performOperation(in byte[] request);
   const int AUTH_TOKEN_MAC_LENGTH = 32;
 }
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
index 63bad2c..88c479c 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -36,7 +36,7 @@
 @VintfStability
 interface IRemotelyProvisionedComponent {
   byte[] generateEcdsaP256KeyPair(in boolean testMode, out android.hardware.security.keymint.MacedPublicKey macedPublicKey);
-  void generateCertificateRequest(in boolean testMode, in android.hardware.security.keymint.MacedPublicKey[] keysToSign, in byte[] endpointEncryptionCertChain, in byte[] challenge, out byte[] keysToSignMac, out android.hardware.security.keymint.ProtectedData protectedData);
+  byte[] generateCertificateRequest(in boolean testMode, in android.hardware.security.keymint.MacedPublicKey[] keysToSign, in byte[] endpointEncryptionCertChain, in byte[] challenge, out android.hardware.security.keymint.DeviceInfo deviceInfo, out android.hardware.security.keymint.ProtectedData protectedData);
   const int STATUS_FAILED = 1;
   const int STATUS_INVALID_MAC = 2;
   const int STATUS_PRODUCTION_KEY_IN_TEST_REQUEST = 3;
diff --git a/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl b/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
new file mode 100644
index 0000000..3ea14a1
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.hardware.security.keymint;
+
+/**
+ * DeviceInfo contains information about the device that's fed in as AAD in the signature of the
+ * device private key over the MAC key used for the bundle of public keys. These values are intended
+ * to be checked by the server to verify that the certificate signing request crafted by
+ * an IRemotelyProvisionedComponent HAL instance is coming from the expected device based
+ * on values initially uploaded during device manufacture in the factory.
+ * @hide
+ */
+@VintfStability
+parcelable DeviceInfo {
+    /**
+     * DeviceInfo is a CBOR Map structure described by the following CDDL.
+     *
+     *     DeviceInfo = {
+     *         ? "brand" : tstr,
+     *         ? "manufacturer" : tstr,
+     *         ? "product" : tstr,
+     *         ? "model" : tstr,
+     *         ? "board" : tstr,
+     *         ? "vb_state" : "green" / "yellow" / "orange",    // Taken from the AVB values
+     *         ? "bootloader_state" : "locked" / "unlocked",    // Taken from the AVB values
+     *         ? "os_version" : tstr,                    // Same as android.os.Build.VERSION.release
+     *         ? "system_patch_level" : uint,                   // YYYYMMDD
+     *         ? "boot_patch_level" : uint,                     // YYYYMMDD
+     *         ? "vendor_patch_level" : uint,                   // YYYYMMDD
+     *     }
+     */
+    byte[] deviceInfo;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 3100b23..17aab25 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -762,6 +762,27 @@
      */
     void earlyBootEnded();
 
+    /*
+     * Called by the client to get a wrapped per-boot ephemeral key from a wrapped storage key.
+     * Clients will then use the returned per-boot ephemeral key in place of the wrapped storage
+     * key. Whenever the hardware is presented with a per-boot ephemeral key for an operation, it
+     * must use the storage key associated with that ephemeral key to perform the requested
+     * operation.
+     *
+     * Implementations should return ErrorCode::UNIMPLEMENTED if they don't support wrapped storage
+     * keys.
+     *
+     * Implementations should return ErrorCode::INVALID_ARGUMENT (as a ServiceSpecificException)
+     * if the input key blob doesn't represent a valid long-lived wrapped storage key.
+     *
+     * @param storageKeyBlob is the wrapped storage key for which the client wants a per-boot
+     *        ephemeral key
+     *
+     * @return a buffer containing the per-boot ephemeral keyblob that should henceforth be used in
+     *         place of the input storageKeyBlob
+     */
+    byte[] convertStorageKeyToEphemeral(in byte[] storageKeyBlob);
+
     /**
      * Called by the client to perform a KeyMint operation.
      *
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
index 5c8ca6d..1cb50ba 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.security.keymint;
 
+import android.hardware.security.keymint.DeviceInfo;
 import android.hardware.security.keymint.MacedPublicKey;
 import android.hardware.security.keymint.ProtectedData;
 
@@ -257,7 +258,7 @@
      * @param out ProtectedData contains the encrypted BCC and the ephemeral MAC key used to
      *        authenticate the keysToSign (see keysToSignMac output argument).
      */
-    void generateCertificateRequest(in boolean testMode, in MacedPublicKey[] keysToSign,
-            in byte[] endpointEncryptionCertChain, in byte[] challenge, out byte[] keysToSignMac,
+    byte[] generateCertificateRequest(in boolean testMode, in MacedPublicKey[] keysToSign,
+            in byte[] endpointEncryptionCertChain, in byte[] challenge, out DeviceInfo deviceInfo,
             out ProtectedData protectedData);
 }
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
index c589ca1..f3c5477 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
@@ -53,13 +53,36 @@
 
     /**
      * If the generated/imported key is an asymmetric key, `certificateChain` will contain a chain
-     * of one or more certificates.  If the key parameters provided to the generate/import method
-     * contains Tag::ATTESTATION_CHALLENGE the first certificate will contain an attestation
-     * extension, and will be signed by a factory-installed attestation key and followed by a chain
-     * of certificates leading to an authoritative root.  If there is no attestation challenge, only
-     * one certificate will be returned, and it will be self-signed or contain a fake signature,
-     * depending on whether the key has KeyPurpose::SIGN.  If the generated key is symmetric,
-     * certificateChain will be empty.
+     * of one or more certificates.
+     *
+     * There are a few variations in what is contained in `certificateChain`, depending on whether
+     * the caller requested attestation, whether they provided an attestation key (via the
+     * `attestationKey` parameter of `generateKey()`, `importKey()` or `importWrappedKey()`), and in
+     * the non-attestaion case, whether the key can self-sign.
+     *
+     * 1.  Attestation with factory key.  If Tag::ATTESTATION_CHALLENGE is provided and the
+     *     `attestationKey` parameter on the generate/import call is null, the returned certificate
+     *     chain must contain an attestation certificate signed with a factory-provisioned
+     *     attestation key, and the full certificate chain for that factory-provisioned attestation
+     *     key.
+     *
+     * 2.  Attestation with caller-provided key.  If Tag::ATTESTATION_CHALLENGE is provided and the
+     *     `attestationKey` parameter on the generat/import call is non-null and contains the key
+     *     blob of a key with KeyPurpose::ATTEST_KEY, the returned certificate chain must contain
+     *     only an attestation certificate signed with the specified key.  The caller must know the
+     *     certificate chain for the provided key.
+     *
+     * 3.  Non-attestation with signing key.  If Tag::ATTESTATION_CHALLENGE is not provided and the
+     *     generated/imported key has KeyPurpose::SIGN, then the returned certificate chain must
+     *     contain only a single self-signed certificate with no attestation extension.
+     *
+     * 4.  Non-attestation with non-signing key.  If TAG::ATTESTATION_CHALLENGE is not provided and
+     *     the generated/imported key does not have KeyPurpose::SIGN, then the returned certificate
+     *     chain must contain only a single certificate with an empty signature and no attestation
+     *     extension.
+     *
+     * 5.  Symmetric key.  If the generated/imported key is symmetric, the certificate chain must be
+     *     empty.
      */
     Certificate[] certificateChain;
 }
diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp
index 63b91fe..ebdc9b7 100644
--- a/security/keymint/aidl/default/Android.bp
+++ b/security/keymint/aidl/default/Android.bp
@@ -39,6 +39,17 @@
     srcs: [
         "service.cpp",
     ],
+    required: [
+        "RemoteProvisioner",
+        "android.hardware.hardware_keystore.xml",
+    ],
+}
+
+prebuilt_etc {
+    name: "android.hardware.hardware_keystore.xml",
+    sub_dir: "permissions",
+    vendor: true,
+    src: "android.hardware.hardware_keystore.xml",
 }
 
 cc_library {
diff --git a/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp b/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp
index 749f0bc..4dbaa05 100644
--- a/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp
+++ b/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp
@@ -322,8 +322,8 @@
 
 ScopedAStatus RemotelyProvisionedComponent::generateCertificateRequest(
         bool testMode, const vector<MacedPublicKey>& keysToSign,
-        const bytevec& endpointEncCertChain, const bytevec& challenge, bytevec* keysToSignMac,
-        ProtectedData* protectedData) {
+        const bytevec& endpointEncCertChain, const bytevec& challenge, DeviceInfo* deviceInfo,
+        ProtectedData* protectedData, bytevec* keysToSignMac) {
     auto pubKeysToSign = validateAndExtractPubkeys(testMode, keysToSign,
                                                    testMode ? remote_prov::kTestMacKey : macKey_);
     if (!pubKeysToSign.isOk()) return pubKeysToSign.moveError();
@@ -343,11 +343,12 @@
         bcc = bcc_.clone();
     }
 
+    deviceInfo->deviceInfo = createDeviceInfo();
     auto signedMac = constructCoseSign1(devicePrivKey /* Signing key */,  //
                                         ephemeralMacKey /* Payload */,
                                         cppbor::Array() /* AAD */
                                                 .add(challenge)
-                                                .add(createDeviceInfo())
+                                                .add(deviceInfo->deviceInfo)
                                                 .encode());
     if (!signedMac) return Status(signedMac.moveMessage());
 
diff --git a/security/keymint/aidl/default/RemotelyProvisionedComponent.h b/security/keymint/aidl/default/RemotelyProvisionedComponent.h
index e8d2343..65b1bbc 100644
--- a/security/keymint/aidl/default/RemotelyProvisionedComponent.h
+++ b/security/keymint/aidl/default/RemotelyProvisionedComponent.h
@@ -39,8 +39,8 @@
                                              const std::vector<MacedPublicKey>& keysToSign,
                                              const std::vector<uint8_t>& endpointEncCertChain,
                                              const std::vector<uint8_t>& challenge,
-                                             std::vector<uint8_t>* keysToSignMac,
-                                             ProtectedData* protectedData) override;
+                                             DeviceInfo* deviceInfo, ProtectedData* protectedData,
+                                             std::vector<uint8_t>* keysToSignMac) override;
 
   private:
     // TODO(swillden): Move these into an appropriate Context class.
diff --git a/security/keymint/aidl/default/android.hardware.hardware_keystore.xml b/security/keymint/aidl/default/android.hardware.hardware_keystore.xml
new file mode 100644
index 0000000..e5a9345
--- /dev/null
+++ b/security/keymint/aidl/default/android.hardware.hardware_keystore.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<permissions>
+  <feature name="android.hardware.hardware_keystore" version="100" />
+</permissions>
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 50e6cce..9b797de 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -227,11 +227,12 @@
 TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
     bool testMode = true;
     bytevec keysToSignMac;
+    DeviceInfo deviceInfo;
     ProtectedData protectedData;
     auto challenge = randomBytes(32);
-    auto status = provisionable_->generateCertificateRequest(testMode, {} /* keysToSign */,
-                                                             eekChain_.chain, challenge,
-                                                             &keysToSignMac, &protectedData);
+    auto status = provisionable_->generateCertificateRequest(
+            testMode, {} /* keysToSign */, eekChain_.chain, challenge, &deviceInfo, &protectedData,
+            &keysToSignMac);
     ASSERT_TRUE(status.isOk()) << status.getMessage();
 
     auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
@@ -297,11 +298,12 @@
 TEST_P(CertificateRequestTest, EmptyRequest_prodMode) {
     bool testMode = false;
     bytevec keysToSignMac;
+    DeviceInfo deviceInfo;
     ProtectedData protectedData;
     auto challenge = randomBytes(32);
-    auto status = provisionable_->generateCertificateRequest(testMode, {} /* keysToSign */,
-                                                             eekChain_.chain, challenge,
-                                                             &keysToSignMac, &protectedData);
+    auto status = provisionable_->generateCertificateRequest(
+            testMode, {} /* keysToSign */, eekChain_.chain, challenge, &deviceInfo, &protectedData,
+            &keysToSignMac);
     ASSERT_FALSE(status.isOk());
     ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
 }
@@ -314,10 +316,12 @@
     generateKeys(testMode, 4 /* numKeys */);
 
     bytevec keysToSignMac;
+    DeviceInfo deviceInfo;
     ProtectedData protectedData;
     auto challenge = randomBytes(32);
-    auto status = provisionable_->generateCertificateRequest(
-            testMode, keysToSign_, eekChain_.chain, challenge, &keysToSignMac, &protectedData);
+    auto status = provisionable_->generateCertificateRequest(testMode, keysToSign_, eekChain_.chain,
+                                                             challenge, &deviceInfo, &protectedData,
+                                                             &keysToSignMac);
     ASSERT_TRUE(status.isOk()) << status.getMessage();
 
     auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
@@ -384,10 +388,12 @@
     generateKeys(testMode, 4 /* numKeys */);
 
     bytevec keysToSignMac;
+    DeviceInfo deviceInfo;
     ProtectedData protectedData;
     auto challenge = randomBytes(32);
-    auto status = provisionable_->generateCertificateRequest(
-            testMode, keysToSign_, eekChain_.chain, challenge, &keysToSignMac, &protectedData);
+    auto status = provisionable_->generateCertificateRequest(testMode, keysToSign_, eekChain_.chain,
+                                                             challenge, &deviceInfo, &protectedData,
+                                                             &keysToSignMac);
     ASSERT_FALSE(status.isOk());
     ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
 }
@@ -400,11 +406,12 @@
     generateKeys(false /* testMode */, 2 /* numKeys */);
 
     bytevec keysToSignMac;
+    DeviceInfo deviceInfo;
     ProtectedData protectedData;
     auto challenge = randomBytes(32);
-    auto status = provisionable_->generateCertificateRequest(true /* testMode */, keysToSign_,
-                                                             eekChain_.chain, challenge,
-                                                             &keysToSignMac, &protectedData);
+    auto status = provisionable_->generateCertificateRequest(
+            true /* testMode */, keysToSign_, eekChain_.chain, challenge, &deviceInfo,
+            &protectedData, &keysToSignMac);
     ASSERT_FALSE(status.isOk());
     ASSERT_EQ(status.getServiceSpecificError(),
               BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST);
@@ -418,10 +425,11 @@
     generateKeys(true /* testMode */, 2 /* numKeys */);
 
     bytevec keysToSignMac;
+    DeviceInfo deviceInfo;
     ProtectedData protectedData;
     auto status = provisionable_->generateCertificateRequest(
             false /* testMode */, keysToSign_, eekChain_.chain, randomBytes(32) /* challenge */,
-            &keysToSignMac, &protectedData);
+            &deviceInfo, &protectedData, &keysToSignMac);
     ASSERT_FALSE(status.isOk());
     ASSERT_EQ(status.getServiceSpecificError(),
               BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
diff --git a/security/secureclock/aidl/vts/functional/Android.bp b/security/secureclock/aidl/vts/functional/Android.bp
index 6dfa417..56c8e1d 100644
--- a/security/secureclock/aidl/vts/functional/Android.bp
+++ b/security/secureclock/aidl/vts/functional/Android.bp
@@ -39,11 +39,11 @@
     shared_libs: [
         "libbinder_ndk",
         "libcrypto",
-        "libkeymint",
     ],
     static_libs: [
         "android.hardware.security.keymint-V1-ndk_platform",
         "android.hardware.security.secureclock-V1-ndk_platform",
+        "libkeymint",
     ],
     test_suites: [
         "general-tests",
diff --git a/security/secureclock/aidl/vts/functional/AndroidTest.xml b/security/secureclock/aidl/vts/functional/AndroidTest.xml
deleted file mode 100644
index 4861c7c..0000000
--- a/security/secureclock/aidl/vts/functional/AndroidTest.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<configuration description="Runs VtsAidlSecureClockTargetTest.">
-    <option name="test-suite-tag" value="apct" />
-    <option name="test-suite-tag" value="apct-native" />
-
-    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
-    </target_preparer>
-
-    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
-        <option name="cleanup" value="true" />
-        <option name="push"
-                value="VtsAidlSecureClockTargetTest->/data/local/tmp/VtsAidlSecureClockTargetTest" />
-    </target_preparer>
-
-    <test class="com.android.tradefed.testtype.GTest" >
-        <option name="native-test-device-path" value="/data/local/tmp" />
-        <option name="module-name" value="VtsAidlSecureClockTargetTest" />
-        <option name="native-test-timeout" value="900000"/>
-    </test>
-</configuration>
diff --git a/security/sharedsecret/aidl/aidl_api/android.hardware.security.sharedsecret/current/android/hardware/security/sharedsecret/SharedSecretParameters.aidl b/security/sharedsecret/aidl/aidl_api/android.hardware.security.sharedsecret/current/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
index b50ddcd..e15fd49 100644
--- a/security/sharedsecret/aidl/aidl_api/android.hardware.security.sharedsecret/current/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
+++ b/security/sharedsecret/aidl/aidl_api/android.hardware.security.sharedsecret/current/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
@@ -33,7 +33,7 @@
 
 package android.hardware.security.sharedsecret;
 /* @hide */
-@VintfStability
+@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
 parcelable SharedSecretParameters {
   byte[] seed;
   byte[] nonce;
diff --git a/security/sharedsecret/aidl/android/hardware/security/sharedsecret/ISharedSecret.aidl b/security/sharedsecret/aidl/android/hardware/security/sharedsecret/ISharedSecret.aidl
index 4303dc5..eca8d87 100644
--- a/security/sharedsecret/aidl/android/hardware/security/sharedsecret/ISharedSecret.aidl
+++ b/security/sharedsecret/aidl/android/hardware/security/sharedsecret/ISharedSecret.aidl
@@ -22,8 +22,8 @@
  * An ISharedSecret enables any service that implements this interface to establish a shared secret
  * with one or more other services such as ISecureClock, TEE IKeymintDevice, StrongBox
  * IKeymintDevice, etc. The shared secret is a 256-bit HMAC key and it is further used to generate
- * secure tokens with integrity protection. There are two steps to establish a shared secret between
- * the collaborating services:
+ * secure tokens with integrity protection. There are three steps to establish a shared secret
+ * between the collaborating services:
  *
  * Step 1: During Android startup the system calls each service that implements this interface to
  * get the shared secret parameters. This is done using getSharedSecretParameters method defined
@@ -64,11 +64,11 @@
 
     /**
      * This method is the second and final step in the process for agreeing on a shared key.  It is
-     * called by Android during startup.  The system calls it on each of the keymint services, and
-     * sends to it all of the SharedSecretParameters returned by all keymint services.
+     * called by Android during startup.  The system calls it on each of the HAL instances, and
+     * sends to it all of the SharedSecretParameters returned by all HAL instances.
      *
-     * This method computes the shared 32-byte HMAC key ``H'' as follows (all keymint services
-     * instances perform the same computation to arrive at the same result):
+     * This method computes the shared 32-byte HMAC key ``H'' as follows (all HAL instances perform
+     * the same computation to arrive at the same result):
      *
      *     H = CKDF(key = K,
      *              context = P1 || P2 || ... || Pn,
@@ -98,16 +98,16 @@
      * Note that the label "KeymasterSharedMac" is the 18-byte UTF-8 encoding of the string.
      *
      * @param params is an array of SharedSecretParameters The lexicographically sorted
-     * SharedSecretParameters data returned by all keymint services when getSharedSecretParameters
+     * SharedSecretParameters data returned by all HAL instances when getSharedSecretParameters
      * was called.
      *
-     * @return sharingCheck A 32-byte value used to verify that all the keymint services have
+     * @return sharingCheck A 32-byte value used to verify that all the HAL instances have
      *         computed the same shared HMAC key.  The sharingCheck value is computed as follows:
      *
      *             sharingCheck = HMAC(H, KEY_CHECK_LABEL)
      *
      *         The string is UTF-8 encoded, 27 bytes in length.  If the returned values of all
-     *         keymint services don't match, clients must assume that HMAC agreement
+     *         HAL instances don't match, clients must assume that HMAC agreement
      *         failed.
      */
     byte[] computeSharedSecret(in SharedSecretParameters[] params);
diff --git a/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl b/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
index a5eec40..8144699 100644
--- a/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
+++ b/security/sharedsecret/aidl/android/hardware/security/sharedsecret/SharedSecretParameters.aidl
@@ -24,6 +24,7 @@
  * @hide
  */
 @VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
 parcelable SharedSecretParameters {
     /**
      * Either empty or contains a non zero persistent value that is associated with the pre-shared
diff --git a/security/sharedsecret/aidl/vts/functional/Android.bp b/security/sharedsecret/aidl/vts/functional/Android.bp
index 1bc5beb..d3747fc 100644
--- a/security/sharedsecret/aidl/vts/functional/Android.bp
+++ b/security/sharedsecret/aidl/vts/functional/Android.bp
@@ -39,11 +39,11 @@
     shared_libs: [
         "libbinder_ndk",
         "libcrypto",
-        "libkeymint",
     ],
     static_libs: [
         "android.hardware.security.keymint-V1-ndk_platform",
         "android.hardware.security.sharedsecret-V1-ndk_platform",
+        "libkeymint",
     ],
     test_suites: [
         "general-tests",
diff --git a/security/sharedsecret/aidl/vts/functional/AndroidTest.xml b/security/sharedsecret/aidl/vts/functional/AndroidTest.xml
deleted file mode 100644
index c6697bc..0000000
--- a/security/sharedsecret/aidl/vts/functional/AndroidTest.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<configuration description="Runs VtsAidlSharedSecretTargetTest.">
-    <option name="test-suite-tag" value="apct" />
-    <option name="test-suite-tag" value="apct-native" />
-
-    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
-    </target_preparer>
-
-    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
-        <option name="cleanup" value="true" />
-        <option name="push"
-                value="VtsAidlSharedSecretTargetTest->/data/local/tmp/VtsAidlSharedSecretTargetTest" />
-    </target_preparer>
-
-    <test class="com.android.tradefed.testtype.GTest" >
-        <option name="native-test-device-path" value="/data/local/tmp" />
-        <option name="module-name" value="VtsAidlSharedSecretTargetTest" />
-        <option name="native-test-timeout" value="900000"/>
-    </test>
-</configuration>
diff --git a/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp b/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
index 83f6ef3..8426120 100644
--- a/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
+++ b/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
@@ -114,14 +114,14 @@
     const vector<shared_ptr<ISharedSecret>>& allSharedSecrets() { return allSharedSecrets_; }
 
     static void SetUpTestCase() {
-        if (allSharedSecrets_.empty()) {
-            auto names = ::android::getAidlHalInstanceNames(ISharedSecret::descriptor);
-            for (const auto& name : names) {
-                auto servicePtr = getSharedSecretService(name.c_str());
-                if (servicePtr != nullptr) allSharedSecrets_.push_back(std::move(servicePtr));
-            }
+        ASSERT_TRUE(allSharedSecrets_.empty()) << "The Shared Secret vector is not empty.";
+        auto names = ::android::getAidlHalInstanceNames(ISharedSecret::descriptor);
+        for (const auto& name : names) {
+            auto servicePtr = getSharedSecretService(name.c_str());
+            if (servicePtr != nullptr) allSharedSecrets_.push_back(std::move(servicePtr));
         }
     }
+
     static void TearDownTestCase() {}
     void SetUp() override {}
     void TearDown() override {}
@@ -134,6 +134,9 @@
 
 TEST_F(SharedSecretAidlTest, GetParameters) {
     auto sharedSecrets = allSharedSecrets();
+    if (sharedSecrets.empty()) {
+        GTEST_SKIP() << "Skipping the test because no shared secret service is found.";
+    }
     for (auto sharedSecret : sharedSecrets) {
         auto result1 = getSharedSecretParameters(sharedSecret);
         EXPECT_EQ(ErrorCode::OK, result1.error);
@@ -148,14 +151,18 @@
 }
 
 TEST_F(SharedSecretAidlTest, ComputeSharedSecret) {
+    auto sharedSecrets = allSharedSecrets();
+    if (sharedSecrets.empty()) {
+        GTEST_SKIP() << "Skipping the test as no shared secret service is found.";
+    }
     auto params = getAllSharedSecretParameters();
-    ASSERT_EQ(allSharedSecrets().size(), params.size())
+    ASSERT_EQ(sharedSecrets.size(), params.size())
             << "One or more shared secret services failed to provide parameters.";
     auto nonces = copyNonces(params);
-    EXPECT_EQ(allSharedSecrets().size(), nonces.size());
+    EXPECT_EQ(sharedSecrets.size(), nonces.size());
     std::sort(nonces.begin(), nonces.end());
     std::unique(nonces.begin(), nonces.end());
-    EXPECT_EQ(allSharedSecrets().size(), nonces.size());
+    EXPECT_EQ(sharedSecrets.size(), nonces.size());
 
     auto responses = computeAllSharedSecrets(params);
     ASSERT_GT(responses.size(), 0U);
@@ -163,7 +170,7 @@
 
     // Do it a second time.  Should get the same answers.
     params = getAllSharedSecretParameters();
-    ASSERT_EQ(allSharedSecrets().size(), params.size())
+    ASSERT_EQ(sharedSecrets.size(), params.size())
             << "One or more shared secret services failed to provide parameters.";
 
     responses = computeAllSharedSecrets(params);
@@ -188,10 +195,14 @@
 }
 
 TEST_F(SharedSecretAidlTest, ComputeSharedSecretCorruptNonce) {
+    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(allSharedSecrets().size(), params.size())
+    ASSERT_EQ(sharedSecrets.size(), params.size())
             << "One or more shared secret services failed to provide parameters.";
 
     // All should be well in the normal case
@@ -224,9 +235,13 @@
 }
 
 TEST_F(SharedSecretAidlTest, ComputeSharedSecretCorruptSeed) {
+    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(allSharedSecrets().size(), params.size())
+    ASSERT_EQ(sharedSecrets.size(), params.size())
             << "One or more shared secret service failed to provide parameters.";
 
     // All should be well in the normal case
diff --git a/sensors/common/utils/EventMessageQueueWrapper.h b/sensors/common/utils/EventMessageQueueWrapper.h
index c4f92c8..63e4eb0 100644
--- a/sensors/common/utils/EventMessageQueueWrapper.h
+++ b/sensors/common/utils/EventMessageQueueWrapper.h
@@ -33,7 +33,7 @@
 namespace V2_1 {
 namespace implementation {
 
-class EventMessageQueueWrapperBase : public RefBase {
+class EventMessageQueueWrapperBase {
   public:
     virtual ~EventMessageQueueWrapperBase() {}
 
diff --git a/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h
index 8cf5003..47a8cc0 100644
--- a/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h
+++ b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h
@@ -462,6 +462,7 @@
 
     // Wait for events to be written back to the Event FMQ
     callback.waitForEvents(sensors, milliseconds(1000) /* timeout */);
+    getEnvironment()->unregisterCallback();
 
     for (const auto& s : sensors) {
         auto events = callback.getEvents(s.sensorHandle);
@@ -485,7 +486,6 @@
         ASSERT_EQ(lastEvent.u.vec3.status, injectedEvent.u.vec3.status);
     }
 
-    getEnvironment()->unregisterCallback();
     ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
 }
 
@@ -603,7 +603,7 @@
                          << " type=" << static_cast<int>(sensor.type) << " name=" << sensor.name);
 
             Result flushResult = flush(sensor.sensorHandle);
-            ASSERT_EQ(flushResult, expectedResponse);
+            EXPECT_EQ(flushResult, expectedResponse);
         }
     }
 
diff --git a/tv/cec/1.0/vts/functional/Android.bp b/tv/cec/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..9a2c714
--- /dev/null
+++ b/tv/cec/1.0/vts/functional/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 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.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalTvCecV1_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalTvCecV1_0TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.tv.cec@1.0",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    disable_framework: true,
+}
diff --git a/tv/cec/1.0/vts/functional/README.md b/tv/cec/1.0/vts/functional/README.md
new file mode 100644
index 0000000..aecd6a6
--- /dev/null
+++ b/tv/cec/1.0/vts/functional/README.md
@@ -0,0 +1,30 @@
+# CEC VTS testing for Android TV devices
+
+Validate HDMI CEC VTS (android.hardware.tv.cec@1.0) functionality.
+
+### Setup:
+
+Running these CEC VTS tests requires an Android playback, TV or audio device connected to the host machine.
+
+![drawing](setup.png)
+
+### Building
+
+From the Android root folder, after choosing the lunch combo, use `make vts` to build VTS.
+
+### Automation
+
+On the host machine, ensure that the [software requirements](https://codelabs.developers.google.com/codelabs/android-lab/#2) for python SDK are met.
+
+Given the setup described above you can run tests with any of the following commands:
+
+1. Using vts-tradefed :
+```
+cd $ANDROID_BUILD_TOP/out/host/linux-x86/vts/android-vts/tools
+./vts-tradefed run commandAndExit vts -m VtsHalTvCecV1_0TargetTest
+```
+2. Using atest
+```
+atest VtsHalTvCecV1_0TargetTest
+```
+Note : atest internally handles building as well. To update the test use '-c' (clear cache) option
diff --git a/tv/cec/1.0/vts/functional/VtsHalTvCecV1_0TargetTest.cpp b/tv/cec/1.0/vts/functional/VtsHalTvCecV1_0TargetTest.cpp
new file mode 100644
index 0000000..7b42689
--- /dev/null
+++ b/tv/cec/1.0/vts/functional/VtsHalTvCecV1_0TargetTest.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 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 "HdmiCec_hal_test"
+#include <android-base/logging.h>
+
+#include <android/hardware/tv/cec/1.0/IHdmiCec.h>
+#include <android/hardware/tv/cec/1.0/types.h>
+#include <utils/Log.h>
+#include <sstream>
+#include <vector>
+
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_death_recipient;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::tv::cec::V1_0::CecDeviceType;
+using ::android::hardware::tv::cec::V1_0::CecLogicalAddress;
+using ::android::hardware::tv::cec::V1_0::CecMessage;
+using ::android::hardware::tv::cec::V1_0::HdmiPortInfo;
+using ::android::hardware::tv::cec::V1_0::HdmiPortType;
+using ::android::hardware::tv::cec::V1_0::IHdmiCec;
+using ::android::hardware::tv::cec::V1_0::OptionKey;
+using ::android::hardware::tv::cec::V1_0::Result;
+using ::android::hardware::tv::cec::V1_0::SendMessageResult;
+
+#define CEC_VERSION 0x05
+#define INCORRECT_VENDOR_ID 0x00
+#define TV_PHYSICAL_ADDRESS 0x0000
+
+// The main test class for TV CEC HAL.
+class HdmiCecTest : public ::testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        hdmiCec = IHdmiCec::getService(GetParam());
+        ASSERT_NE(hdmiCec, nullptr);
+        ALOGI("%s: getService() for hdmiCec is %s", __func__,
+              hdmiCec->isRemote() ? "remote" : "local");
+
+        hdmiCec_death_recipient = new HdmiCecDeathRecipient();
+        ASSERT_NE(hdmiCec_death_recipient, nullptr);
+        ASSERT_TRUE(hdmiCec->linkToDeath(hdmiCec_death_recipient, 0).isOk());
+    }
+
+    std::vector<int> getDeviceTypes() {
+        std::vector<int> deviceTypes;
+        FILE* p = popen("getprop ro.hdmi.device_type", "re");
+        if (p) {
+            char* line = NULL;
+            size_t len = 0;
+            if (getline(&line, &len, p) > 0) {
+                std::istringstream stream(line);
+                std::string number{};
+                while (std::getline(stream, number, ',')) {
+                    deviceTypes.push_back(stoi(number));
+                }
+            }
+            pclose(p);
+        }
+        return deviceTypes;
+    }
+
+    bool hasDeviceType(CecDeviceType type) {
+        std::vector<int> deviceTypes = getDeviceTypes();
+        for (auto deviceType = deviceTypes.begin(); deviceType != deviceTypes.end(); ++deviceType) {
+            if (*deviceType == (int)type) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    class HdmiCecDeathRecipient : public hidl_death_recipient {
+      public:
+        void serviceDied(uint64_t /*cookie*/,
+                         const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) override {
+            FAIL();
+        }
+    };
+
+    sp<IHdmiCec> hdmiCec;
+    sp<HdmiCecDeathRecipient> hdmiCec_death_recipient;
+};
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HdmiCecTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, HdmiCecTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IHdmiCec::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+TEST_P(HdmiCecTest, ClearAddLogicalAddress) {
+    hdmiCec->clearLogicalAddress();
+    Return<Result> ret = hdmiCec->addLogicalAddress(CecLogicalAddress::PLAYBACK_3);
+    EXPECT_EQ(ret, Result::SUCCESS);
+}
+
+TEST_P(HdmiCecTest, PhysicalAddress) {
+    Result result;
+    uint16_t addr;
+    Return<void> ret = hdmiCec->getPhysicalAddress([&result, &addr](Result res, uint16_t paddr) {
+        result = res;
+        addr = paddr;
+    });
+    EXPECT_TRUE(ret.isOk());
+    EXPECT_EQ(result, Result::SUCCESS);
+    if (!hasDeviceType(CecDeviceType::TV)) {
+        EXPECT_NE(addr, TV_PHYSICAL_ADDRESS);
+    }
+}
+
+TEST_P(HdmiCecTest, SendMessage) {
+    CecMessage message;
+    message.initiator = CecLogicalAddress::PLAYBACK_1;
+    message.destination = CecLogicalAddress::BROADCAST;
+    message.body.resize(1);
+    message.body[0] = 131;
+    SendMessageResult ret = hdmiCec->sendMessage(message);
+    EXPECT_EQ(ret, SendMessageResult::SUCCESS);
+}
+
+TEST_P(HdmiCecTest, CecVersion) {
+    Return<int32_t> ret = hdmiCec->getCecVersion();
+    EXPECT_GE(ret, CEC_VERSION);
+}
+
+TEST_P(HdmiCecTest, VendorId) {
+    Return<uint32_t> ret = hdmiCec->getVendorId();
+    EXPECT_NE(ret, INCORRECT_VENDOR_ID);
+}
+
+TEST_P(HdmiCecTest, GetPortInfo) {
+    hidl_vec<HdmiPortInfo> ports;
+    Return<void> ret =
+            hdmiCec->getPortInfo([&ports](hidl_vec<HdmiPortInfo> list) { ports = list; });
+    EXPECT_TRUE(ret.isOk());
+    bool cecSupportedOnDevice = false;
+    for (size_t i = 0; i < ports.size(); ++i) {
+        EXPECT_TRUE((ports[i].type == HdmiPortType::OUTPUT) ||
+                    (ports[i].type == HdmiPortType::INPUT));
+        if (ports[i].portId == 0) {
+            ALOGW("%s: Port id should start from 1", __func__);
+        }
+        cecSupportedOnDevice = cecSupportedOnDevice | ports[i].cecSupported;
+    }
+    EXPECT_NE(cecSupportedOnDevice, false) << "At least one port should support CEC";
+}
+
+TEST_P(HdmiCecTest, SetOption) {
+    Return<void> ret;
+    ret = hdmiCec->setOption(OptionKey::WAKEUP, false);
+    EXPECT_TRUE(ret.isOk());
+    ret = hdmiCec->setOption(OptionKey::ENABLE_CEC, false);
+    EXPECT_TRUE(ret.isOk());
+    ret = hdmiCec->setOption(OptionKey::SYSTEM_CEC_CONTROL, true);
+    EXPECT_TRUE(ret.isOk());
+    // Restore option keys to their default values
+    ret = hdmiCec->setOption(OptionKey::WAKEUP, true);
+    EXPECT_TRUE(ret.isOk());
+    ret = hdmiCec->setOption(OptionKey::ENABLE_CEC, true);
+    EXPECT_TRUE(ret.isOk());
+    ret = hdmiCec->setOption(OptionKey::SYSTEM_CEC_CONTROL, false);
+    EXPECT_TRUE(ret.isOk());
+}
+
+TEST_P(HdmiCecTest, SetLanguage) {
+    Return<void> ret = hdmiCec->setLanguage("eng");
+    EXPECT_TRUE(ret.isOk());
+}
+
+TEST_P(HdmiCecTest, EnableAudioReturnChannel) {
+    hidl_vec<HdmiPortInfo> ports;
+    Return<void> ret =
+            hdmiCec->getPortInfo([&ports](hidl_vec<HdmiPortInfo> list) { ports = list; });
+    EXPECT_TRUE(ret.isOk());
+    for (size_t i = 0; i < ports.size(); ++i) {
+        if (ports[i].arcSupported) {
+            ret = hdmiCec->enableAudioReturnChannel(ports[i].portId, true);
+            EXPECT_TRUE(ret.isOk());
+        }
+    }
+}
+
+TEST_P(HdmiCecTest, IsConnected) {
+    hidl_vec<HdmiPortInfo> ports;
+    Return<void> ret =
+            hdmiCec->getPortInfo([&ports](hidl_vec<HdmiPortInfo> list) { ports = list; });
+    EXPECT_TRUE(ret.isOk());
+    for (size_t i = 0; i < ports.size(); ++i) {
+        Return<bool> ret = hdmiCec->isConnected(ports[i].portId);
+        EXPECT_TRUE(ret.isOk());
+    }
+}
diff --git a/tv/cec/1.0/vts/functional/setup.png b/tv/cec/1.0/vts/functional/setup.png
new file mode 100644
index 0000000..a64b86c
--- /dev/null
+++ b/tv/cec/1.0/vts/functional/setup.png
Binary files differ