Merge "[SP32.1] Put OffloadControl 1.1 HAL into apex" into sc-dev
diff --git a/audio/7.0/config/api/current.txt b/audio/7.0/config/api/current.txt
index 653531d..4a2ffdb 100644
--- a/audio/7.0/config/api/current.txt
+++ b/audio/7.0/config/api/current.txt
@@ -45,6 +45,8 @@
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_NONE;
+    enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_13POINT_360RA;
+    enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_22POINT2;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT0POINT2;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1POINT2;
@@ -104,6 +106,7 @@
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_FM_TUNER;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_HDMI;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_HDMI_ARC;
+    enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_HDMI_EARC;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_IP;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_LINE;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_LOOPBACK;
@@ -138,6 +141,7 @@
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_FM;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_HDMI;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_HDMI_ARC;
+    enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_HDMI_EARC;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_HEARING_AID;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_IP;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_LINE;
@@ -155,6 +159,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;
@@ -203,6 +213,7 @@
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_DSD;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_DTS;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_DTS_HD;
+    enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_DTS_UHD;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_EVRC;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_EVRCB;
     enum_constant public static final android.audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_EVRCNW;
@@ -488,10 +499,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 ee51aa8..349b9d0 100644
--- a/audio/7.0/config/audio_policy_configuration.xsd
+++ b/audio/7.0/config/audio_policy_configuration.xsd
@@ -253,6 +253,7 @@
             <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES"/>
             <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER"/>
             <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_EARC"/>
             <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
             <xs:enumeration value="AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET"/>
             <xs:enumeration value="AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET"/>
@@ -304,6 +305,7 @@
             <xs:enumeration value="AUDIO_DEVICE_IN_USB_HEADSET"/>
             <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_BLE"/>
             <xs:enumeration value="AUDIO_DEVICE_IN_HDMI_ARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_HDMI_EARC"/>
             <xs:enumeration value="AUDIO_DEVICE_IN_ECHO_REFERENCE"/>
             <xs:enumeration value="AUDIO_DEVICE_IN_BLE_HEADSET"/>
             <xs:enumeration value="AUDIO_DEVICE_IN_DEFAULT"/>
@@ -412,6 +414,7 @@
             <xs:enumeration value="AUDIO_FORMAT_MPEGH_LC_L3"/>
             <xs:enumeration value="AUDIO_FORMAT_MPEGH_LC_L4"/>
             <xs:enumeration value="AUDIO_FORMAT_IEC60958"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS_UHD"/>
         </xs:restriction>
     </xs:simpleType>
     <xs:simpleType name="extendableAudioFormat">
@@ -505,6 +508,8 @@
             <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1"/>
             <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1POINT2"/>
             <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1POINT4"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_13POINT_360RA"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_22POINT2"/>
             <xs:enumeration value="AUDIO_CHANNEL_OUT_MONO_HAPTIC_A"/>
             <xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A"/>
             <xs:enumeration value="AUDIO_CHANNEL_OUT_HAPTIC_AB"/>
@@ -551,11 +556,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..a92a277 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
@@ -94,6 +94,7 @@
         case AudioChannelMask::AUDIO_CHANNEL_OUT_7POINT1POINT4:
         case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_12:
             return 12;
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_13POINT_360RA:
         case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_13:
             return 13;
         case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_14:
@@ -116,6 +117,7 @@
             return 22;
         case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_23:
             return 23;
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_22POINT2:
         case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_24:
             return 24;
         case AudioChannelMask::UNKNOWN:
@@ -155,6 +157,7 @@
         case AudioDevice::AUDIO_DEVICE_OUT_TELEPHONY_TX:
         case AudioDevice::AUDIO_DEVICE_OUT_LINE:
         case AudioDevice::AUDIO_DEVICE_OUT_HDMI_ARC:
+        case AudioDevice::AUDIO_DEVICE_OUT_HDMI_EARC:
         case AudioDevice::AUDIO_DEVICE_OUT_SPDIF:
         case AudioDevice::AUDIO_DEVICE_OUT_FM:
         case AudioDevice::AUDIO_DEVICE_OUT_AUX_LINE:
@@ -197,6 +200,7 @@
         case AudioDevice::AUDIO_DEVICE_IN_USB_HEADSET:
         case AudioDevice::AUDIO_DEVICE_IN_BLUETOOTH_BLE:
         case AudioDevice::AUDIO_DEVICE_IN_HDMI_ARC:
+        case AudioDevice::AUDIO_DEVICE_IN_HDMI_EARC:
         case AudioDevice::AUDIO_DEVICE_IN_ECHO_REFERENCE:
         case AudioDevice::AUDIO_DEVICE_IN_BLE_HEADSET:
         case AudioDevice::AUDIO_DEVICE_IN_DEFAULT:
@@ -287,6 +291,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/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index 70a1a4d..130dfba 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -360,18 +360,43 @@
     return Result::NOT_SUPPORTED;
 }
 
-Return<void> Device::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) {
-    audio_port halPort;
-    HidlUtils::audioPortToHal(port, &halPort);
-    Result retval = analyzeStatus("get_audio_port", mDevice->get_audio_port(mDevice, &halPort));
+template <typename HalPort>
+Return<void> Device::getAudioPortImpl(const AudioPort& port, getAudioPort_cb _hidl_cb,
+                                      int (*halGetter)(audio_hw_device_t*, HalPort*),
+                                      const char* halGetterName) {
+    HalPort halPort;
+    if (status_t status = HidlUtils::audioPortToHal(port, &halPort); status != NO_ERROR) {
+        _hidl_cb(analyzeStatus("audioPortToHal", status), port);
+        return Void();
+    }
+    Result retval = analyzeStatus(halGetterName, halGetter(mDevice, &halPort));
     AudioPort resultPort = port;
     if (retval == Result::OK) {
-        HidlUtils::audioPortFromHal(halPort, &resultPort);
+        if (status_t status = HidlUtils::audioPortFromHal(halPort, &resultPort);
+            status != NO_ERROR) {
+            _hidl_cb(analyzeStatus("audioPortFromHal", status), port);
+            return Void();
+        }
     }
     _hidl_cb(retval, resultPort);
     return Void();
 }
 
+#if MAJOR_VERSION <= 6
+Return<void> Device::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) {
+    return getAudioPortImpl(port, _hidl_cb, mDevice->get_audio_port, "get_audio_port");
+}
+#else
+Return<void> Device::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) {
+    if (version() >= AUDIO_DEVICE_API_VERSION_3_2) {
+        // get_audio_port_v7 is mandatory if legacy HAL support this API version.
+        return getAudioPortImpl(port, _hidl_cb, mDevice->get_audio_port_v7, "get_audio_port_v7");
+    } else {
+        return getAudioPortImpl(port, _hidl_cb, mDevice->get_audio_port, "get_audio_port");
+    }
+}
+#endif
+
 Return<Result> Device::setAudioPortConfig(const AudioPortConfig& config) {
     if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
         struct audio_port_config halPortConfig;
diff --git a/audio/core/all-versions/default/StreamIn.cpp b/audio/core/all-versions/default/StreamIn.cpp
index 599f3c3..2aeee43 100644
--- a/audio/core/all-versions/default/StreamIn.cpp
+++ b/audio/core/all-versions/default/StreamIn.cpp
@@ -413,8 +413,8 @@
 
     // Create and launch the thread.
     auto tempReadThread =
-        std::make_unique<ReadThread>(&mStopReadThread, mStream, tempCommandMQ.get(),
-                                     tempDataMQ.get(), tempStatusMQ.get(), tempElfGroup.get());
+            sp<ReadThread>::make(&mStopReadThread, mStream, tempCommandMQ.get(), tempDataMQ.get(),
+                                 tempStatusMQ.get(), tempElfGroup.get());
     if (!tempReadThread->init()) {
         ALOGW("failed to start reader thread: %s", strerror(-status));
         sendError(Result::INVALID_ARGUMENTS);
@@ -430,7 +430,7 @@
     mCommandMQ = std::move(tempCommandMQ);
     mDataMQ = std::move(tempDataMQ);
     mStatusMQ = std::move(tempStatusMQ);
-    mReadThread = tempReadThread.release();
+    mReadThread = tempReadThread;
     mEfGroup = tempElfGroup.release();
 #if MAJOR_VERSION <= 6
     threadInfo.pid = getpid();
diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp
index 5e4dd2a..6eed3da 100644
--- a/audio/core/all-versions/default/StreamOut.cpp
+++ b/audio/core/all-versions/default/StreamOut.cpp
@@ -398,8 +398,8 @@
 
     // Create and launch the thread.
     auto tempWriteThread =
-        std::make_unique<WriteThread>(&mStopWriteThread, mStream, tempCommandMQ.get(),
-                                      tempDataMQ.get(), tempStatusMQ.get(), tempElfGroup.get());
+            sp<WriteThread>::make(&mStopWriteThread, mStream, tempCommandMQ.get(), tempDataMQ.get(),
+                                  tempStatusMQ.get(), tempElfGroup.get());
     if (!tempWriteThread->init()) {
         ALOGW("failed to start writer thread: %s", strerror(-status));
         sendError(Result::INVALID_ARGUMENTS);
@@ -415,7 +415,7 @@
     mCommandMQ = std::move(tempCommandMQ);
     mDataMQ = std::move(tempDataMQ);
     mStatusMQ = std::move(tempStatusMQ);
-    mWriteThread = tempWriteThread.release();
+    mWriteThread = tempWriteThread;
     mEfGroup = tempElfGroup.release();
 #if MAJOR_VERSION <= 6
     threadInfo.pid = getpid();
diff --git a/audio/core/all-versions/default/include/core/default/Device.h b/audio/core/all-versions/default/include/core/default/Device.h
index 5851fc9..94cad53 100644
--- a/audio/core/all-versions/default/include/core/default/Device.h
+++ b/audio/core/all-versions/default/include/core/default/Device.h
@@ -153,6 +153,10 @@
     std::tuple<Result, AudioPatchHandle> createOrUpdateAudioPatch(
             AudioPatchHandle patch, const hidl_vec<AudioPortConfig>& sources,
             const hidl_vec<AudioPortConfig>& sinks);
+    template <typename HalPort>
+    Return<void> getAudioPortImpl(const AudioPort& port, getAudioPort_cb _hidl_cb,
+                                  int (*halGetter)(audio_hw_device_t*, HalPort*),
+                                  const char* halGetterName);
 
     // Methods from ParametersUtil.
     char* halGetParameters(const char* keys) override;
diff --git a/audio/core/all-versions/default/util/CoreUtils.cpp b/audio/core/all-versions/default/util/CoreUtils.cpp
index 14f76f3..773be21 100644
--- a/audio/core/all-versions/default/util/CoreUtils.cpp
+++ b/audio/core/all-versions/default/util/CoreUtils.cpp
@@ -66,13 +66,13 @@
     CONVERT_CHECKED(
             deviceAddressFromHal(halMicInfo.device, halMicInfo.address, &micInfo->deviceAddress),
             result);
-    size_t chCount;
-    for (chCount = 0; chCount < AUDIO_CHANNEL_COUNT_MAX; ++chCount) {
-        if (halMicInfo.channel_mapping[chCount] == AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED) {
+    int chCount;
+    for (chCount = AUDIO_CHANNEL_COUNT_MAX - 1; chCount >= 0; --chCount) {
+        if (halMicInfo.channel_mapping[chCount] != AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED) {
             break;
         }
     }
-    micInfo->channelMapping.resize(chCount);
+    micInfo->channelMapping.resize(chCount + 1);
     for (size_t ch = 0; ch < micInfo->channelMapping.size(); ch++) {
         micInfo->channelMapping[ch] = AudioMicrophoneChannelMapping(halMicInfo.channel_mapping[ch]);
     }
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/automotive/audiocontrol/aidl/default/Android.bp b/automotive/audiocontrol/aidl/default/Android.bp
index 878bee1..7694bdf 100644
--- a/automotive/audiocontrol/aidl/default/Android.bp
+++ b/automotive/audiocontrol/aidl/default/Android.bp
@@ -27,10 +27,8 @@
     init_rc: ["audiocontrol-default.rc"],
     vintf_fragments: ["audiocontrol-default.xml"],
     vendor: true,
-    generated_headers: ["audio_policy_configuration_V7_0"],
-    generated_sources: ["audio_policy_configuration_V7_0"],
-    header_libs: ["libxsdc-utils"],
     shared_libs: [
+        "android.hardware.audio.common@7.0-enums",
         "android.frameworks.automotive.powerpolicy-V1-ndk_platform",
         "android.hardware.automotive.audiocontrol-V1-ndk_platform",
         "libbase",
@@ -38,7 +36,6 @@
         "libcutils",
         "liblog",
         "libpowerpolicyclient",
-        "libxml2",
     ],
     srcs: [
         "AudioControl.cpp",
diff --git a/automotive/audiocontrol/aidl/default/AudioControl.cpp b/automotive/audiocontrol/aidl/default/AudioControl.cpp
index b076d01..c0bc796 100644
--- a/automotive/audiocontrol/aidl/default/AudioControl.cpp
+++ b/automotive/audiocontrol/aidl/default/AudioControl.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AudioControl"
+// #define LOG_NDEBUG 0
+
 #include "AudioControl.h"
 
 #include <aidl/android/hardware/automotive/audiocontrol/AudioFocusChange.h>
@@ -24,7 +27,7 @@
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
 
-#include <android_audio_policy_configuration_V7_0.h>
+#include <android_audio_policy_configuration_V7_0-enums.h>
 #include <private/android_filesystem_config.h>
 
 #include <stdio.h>
@@ -33,6 +36,7 @@
 
 using ::android::base::EqualsIgnoreCase;
 using ::android::base::ParseInt;
+using ::std::shared_ptr;
 using ::std::string;
 
 namespace xsd {
@@ -68,7 +72,7 @@
         const shared_ptr<IFocusListener>& in_listener) {
     LOG(DEBUG) << "registering focus listener";
 
-    if (in_listener.get()) {
+    if (in_listener) {
         std::atomic_store(&mFocusListener, in_listener);
     } else {
         LOG(ERROR) << "Unexpected nullptr for listener resulting in no-op.";
@@ -80,9 +84,10 @@
     if (isValidValue(value)) {
         // Just log in this default mock implementation
         LOG(INFO) << "Balance set to " << value;
-    } else {
-        LOG(ERROR) << "Balance value out of range -1 to 1 at " << value;
+        return ndk::ScopedAStatus::ok();
     }
+
+    LOG(ERROR) << "Balance value out of range -1 to 1 at " << value;
     return ndk::ScopedAStatus::ok();
 }
 
@@ -90,9 +95,10 @@
     if (isValidValue(value)) {
         // Just log in this default mock implementation
         LOG(INFO) << "Fader set to " << value;
-    } else {
-        LOG(ERROR) << "Fader value out of range -1 to 1 at " << value;
+        return ndk::ScopedAStatus::ok();
     }
+
+    LOG(ERROR) << "Fader value out of range -1 to 1 at " << value;
     return ndk::ScopedAStatus::ok();
 }
 
@@ -194,7 +200,7 @@
     }
 
     string usage = string(args[1]);
-    if (xsd::stringToAudioUsage(usage) == xsd::AudioUsage::UNKNOWN) {
+    if (xsd::isUnknownAudioUsage(usage)) {
         dprintf(fd,
                 "Unknown usage provided: %s. Please see audio_policy_configuration.xsd V7_0 "
                 "for supported values\n",
@@ -236,7 +242,7 @@
     }
 
     string usage = string(args[1]);
-    if (xsd::stringToAudioUsage(usage) == xsd::AudioUsage::UNKNOWN) {
+    if (xsd::isUnknownAudioUsage(usage)) {
         dprintf(fd,
                 "Unknown usage provided: %s. Please see audio_policy_configuration.xsd V7_0 "
                 "for supported values\n",
diff --git a/automotive/audiocontrol/aidl/default/AudioControl.h b/automotive/audiocontrol/aidl/default/AudioControl.h
index ab0b1b3..cca9c44 100644
--- a/automotive/audiocontrol/aidl/default/AudioControl.h
+++ b/automotive/audiocontrol/aidl/default/AudioControl.h
@@ -23,8 +23,6 @@
 
 namespace aidl::android::hardware::automotive::audiocontrol {
 
-using ::std::shared_ptr;
-
 class AudioControl : public BnAudioControl {
   public:
     ndk::ScopedAStatus onAudioFocusChange(const std::string& in_usage, int32_t in_zoneId,
@@ -34,7 +32,7 @@
     ndk::ScopedAStatus onDevicesToMuteChange(
             const std::vector<MutingInfo>& in_mutingInfos) override;
     ndk::ScopedAStatus registerFocusListener(
-            const shared_ptr<IFocusListener>& in_listener) override;
+            const std::shared_ptr<IFocusListener>& in_listener) override;
     ndk::ScopedAStatus setBalanceTowardRight(float in_value) override;
     ndk::ScopedAStatus setFadeTowardFront(float in_value) override;
     binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
@@ -44,7 +42,7 @@
     // a single instance of CarAudioService. As such, it doesn't have explicit serialization.
     // If a different AudioControl implementation were to have multiple threads leveraging this
     // listener, then it should also include mutexes or make the listener atomic.
-    shared_ptr<IFocusListener> mFocusListener;
+    std::shared_ptr<IFocusListener> mFocusListener;
 
     binder_status_t cmdHelp(int fd) const;
     binder_status_t cmdRequestFocus(int fd, const char** args, uint32_t numArgs);
diff --git a/automotive/evs/OWNERS b/automotive/evs/OWNERS
index fec2a3a..6fc5024 100644
--- a/automotive/evs/OWNERS
+++ b/automotive/evs/OWNERS
@@ -1,3 +1,3 @@
 changyeon@google.com
+garysungang@google.com
 haoxiangl@google.com
-swan@google.com
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index b2f8bf6..60b696d 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -78,6 +78,7 @@
     name: "android.hardware.automotive.vehicle@2.0-default-impl-lib",
     vendor: true,
     defaults: ["vhal_v2_0_target_defaults"],
+    cflags: ["-DENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING"],
     srcs: [
         "impl/vhal_v2_0/CommConn.cpp",
         "impl/vhal_v2_0/EmulatedVehicleConnector.cpp",
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 9d0b9ec..abf33a3 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -115,6 +115,28 @@
  */
 const int32_t kMixedTypePropertyForTest =
         0x1111 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
+
+#ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
+/**
+ * Converts the system property to the vendor property.
+ * WARNING: This is only for the end-to-end testing, Should NOT include in the
+ * user build */
+inline constexpr int32_t toVendor(VehicleProperty prop) {
+    return (toInt(prop) & ~toInt(VehiclePropertyGroup::MASK)) | VehiclePropertyGroup::VENDOR;
+}
+
+/**
+ * These properties are used for the end-to-end testing of ClusterHomeService.
+ */
+constexpr int32_t VENDOR_CLUSTER_SWITCH_UI = toVendor(VehicleProperty::CLUSTER_SWITCH_UI);
+constexpr int32_t VENDOR_CLUSTER_DISPLAY_STATE = toVendor(VehicleProperty::CLUSTER_DISPLAY_STATE);
+constexpr int32_t VENDOR_CLUSTER_REPORT_STATE = toVendor(VehicleProperty::CLUSTER_REPORT_STATE);
+constexpr int32_t VENDOR_CLUSTER_REQUEST_DISPLAY =
+        toVendor(VehicleProperty::CLUSTER_REQUEST_DISPLAY);
+constexpr int32_t VENDOR_CLUSTER_NAVIGATION_STATE =
+        toVendor(VehicleProperty::CLUSTER_NAVIGATION_STATE);
+#endif  // ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
+
 /**
  * FakeDataCommand enum defines the supported command type for kGenerateFakeDataControllingProperty.
  * All those commands can be send independently with each other. And each will override the one sent
@@ -439,22 +461,22 @@
                          .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
                          .areaConfigs = {VehicleAreaConfig{
                                                  .areaId = WHEEL_FRONT_LEFT,
-                                                 .minFloatValue = 100.0f,
+                                                 .minFloatValue = 193.0f,
                                                  .maxFloatValue = 300.0f,
                                          },
                                          VehicleAreaConfig{
                                                  .areaId = WHEEL_FRONT_RIGHT,
-                                                 .minFloatValue = 100.0f,
+                                                 .minFloatValue = 193.0f,
                                                  .maxFloatValue = 300.0f,
                                          },
                                          VehicleAreaConfig{
                                                  .areaId = WHEEL_REAR_LEFT,
-                                                 .minFloatValue = 100.0f,
+                                                 .minFloatValue = 193.0f,
                                                  .maxFloatValue = 300.0f,
                                          },
                                          VehicleAreaConfig{
                                                  .areaId = WHEEL_REAR_RIGHT,
-                                                 .minFloatValue = 100.0f,
+                                                 .minFloatValue = 193.0f,
                                                  .maxFloatValue = 300.0f,
                                          }},
                          .minSampleRate = 1.0f,
@@ -464,6 +486,17 @@
 
         {.config =
                  {
+                         .prop = toInt(VehicleProperty::CRITICALLY_LOW_TIRE_PRESSURE),
+                         .access = VehiclePropertyAccess::READ,
+                         .changeMode = VehiclePropertyChangeMode::STATIC,
+                 },
+         .initialAreaValues = {{WHEEL_FRONT_LEFT, {.floatValues = {137.0f}}},
+                               {WHEEL_FRONT_RIGHT, {.floatValues = {137.0f}}},
+                               {WHEEL_REAR_RIGHT, {.floatValues = {137.0f}}},
+                               {WHEEL_REAR_LEFT, {.floatValues = {137.0f}}}}},
+
+        {.config =
+                 {
                          .prop = toInt(VehicleProperty::TIRE_PRESSURE_DISPLAY_UNITS),
                          .access = VehiclePropertyAccess::READ_WRITE,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -668,6 +701,7 @@
         {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
                     .access = VehiclePropertyAccess::READ_WRITE,
                     .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                    .configArray = {160, 280, 5, 605, 825, 10},
                     .areaConfigs = {VehicleAreaConfig{
                                             .areaId = HVAC_LEFT,
                                             .minFloatValue = 16,
@@ -683,6 +717,14 @@
 
         {.config =
                  {
+                         .prop = toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION),
+                         .access = VehiclePropertyAccess::READ_WRITE,
+                         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                 },
+         .initialValue = {.floatValues = {66.2f, (float)VehicleUnit::FAHRENHEIT, 19.0f, 66.5f}}},
+
+        {.config =
+                 {
                          .prop = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE),
                          .access = VehiclePropertyAccess::READ,
                          // TODO(bryaneyler): Support ON_CHANGE as well.
@@ -1064,6 +1106,16 @@
                     .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
          .initialValue = {.stringValue = "Vendor String Property"}},
 
+        {.config = {.prop = toInt(VehicleProperty::ELECTRONIC_TOLL_COLLECTION_CARD_TYPE),
+                    .access = VehiclePropertyAccess::READ,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+         .initialValue = {.int32Values = {0}}},
+
+        {.config = {.prop = toInt(VehicleProperty::ELECTRONIC_TOLL_COLLECTION_CARD_STATUS),
+                    .access = VehiclePropertyAccess::READ,
+                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+         .initialValue = {.int32Values = {0}}},
+
         {.config =
                  {
                          .prop = toInt(VehicleProperty::SUPPORT_CUSTOMIZE_VENDOR_PERMISSION),
@@ -1149,6 +1201,22 @@
         {
                 .config =
                         {
+                                .prop = toInt(VehicleProperty::UNIX_TIME),
+                                .access = VehiclePropertyAccess::READ_WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                        },
+        },
+        {
+                .config =
+                        {
+                                .prop = toInt(VehicleProperty::STORAGE_ENCRYPTION_BINDING_SEED),
+                                .access = VehiclePropertyAccess::READ_WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                        },
+        },
+        {
+                .config =
+                        {
                                 .prop = toInt(VehicleProperty::WATCHDOG_ALIVE),
                                 .access = VehiclePropertyAccess::WRITE,
                                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -1192,7 +1260,7 @@
                                 .prop = toInt(VehicleProperty::CLUSTER_REPORT_STATE),
                                 .access = VehiclePropertyAccess::WRITE,
                                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                                .configArray = {0, 0, 0, 9, 0, 0, 0, 0, 16},
+                                .configArray = {0, 0, 0, 11, 0, 0, 0, 0, 16},
                         },
         },
         {
@@ -1206,11 +1274,55 @@
         {
                 .config =
                         {
-                                .prop = toInt(VehicleProperty::CLUSTER_NAVIGATION_STATE_LEGACY),
+                                .prop = toInt(VehicleProperty::CLUSTER_NAVIGATION_STATE),
                                 .access = VehiclePropertyAccess::WRITE,
                                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
                         },
         },
+#ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
+        // Vendor propetry for E2E ClusterHomeService testing.
+        {
+                .config =
+                        {
+                                .prop = VENDOR_CLUSTER_SWITCH_UI,
+                                .access = VehiclePropertyAccess::WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                        },
+        },
+        {
+                .config =
+                        {
+                                .prop = VENDOR_CLUSTER_DISPLAY_STATE,
+                                .access = VehiclePropertyAccess::WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                        },
+        },
+        {
+                .config =
+                        {
+                                .prop = VENDOR_CLUSTER_REPORT_STATE,
+                                .access = VehiclePropertyAccess::READ,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                                .configArray = {0, 0, 0, 11, 0, 0, 0, 0, 16},
+                        },
+        },
+        {
+                .config =
+                        {
+                                .prop = VENDOR_CLUSTER_REQUEST_DISPLAY,
+                                .access = VehiclePropertyAccess::READ,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                        },
+        },
+        {
+                .config =
+                        {
+                                .prop = VENDOR_CLUSTER_NAVIGATION_STATE,
+                                .access = VehiclePropertyAccess::READ,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                        },
+        },
+#endif  // ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp
index 0ee1835..6b87052 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp
@@ -247,6 +247,28 @@
                     break;
             }
             break;
+
+#ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
+        case toInt(VehicleProperty::CLUSTER_REPORT_STATE):
+        case toInt(VehicleProperty::CLUSTER_REQUEST_DISPLAY):
+        case toInt(VehicleProperty::CLUSTER_NAVIGATION_STATE):
+        case VENDOR_CLUSTER_SWITCH_UI:
+        case VENDOR_CLUSTER_DISPLAY_STATE: {
+            auto updatedPropValue = createVehiclePropValue(getPropType(value.prop), 0);
+            updatedPropValue->prop = value.prop & ~toInt(VehiclePropertyGroup::MASK);
+            if (isSystemProperty(value.prop)) {
+                updatedPropValue->prop |= toInt(VehiclePropertyGroup::VENDOR);
+            } else {
+                updatedPropValue->prop |= toInt(VehiclePropertyGroup::SYSTEM);
+            }
+            updatedPropValue->value = value.value;
+            updatedPropValue->timestamp = elapsedRealtimeNano();
+            updatedPropValue->areaId = value.areaId;
+            onPropertyValueFromCar(*updatedPropValue, updateStatus);
+            return StatusCode::OK;
+        }
+#endif  // ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING
+
         default:
             break;
     }
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 9ecb2d5..e22f9fa 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -641,6 +641,25 @@
         | VehicleArea:WHEEL),
 
     /**
+     * Critically low tire pressure
+     *
+     * This property indicates the critically low pressure threshold for each tire.
+     * It indicates when it is time for tires to be replaced or fixed. The value
+     * must be less than or equal to minFloatValue in TIRE_PRESSURE.
+     * Minimum and maximum property values (that is, minFloatValue, maxFloatValue)
+     * are not applicable to this property.
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     * @unit VehicleUnit:KILOPASCAL
+     */
+    CRITICALLY_LOW_TIRE_PRESSURE = (
+        0x030A
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:FLOAT
+        | VehicleArea:WHEEL),
+
+    /**
      * Currently selected gear
      *
      * This is the gear selected by the user.
@@ -881,6 +900,24 @@
     /**
      * HVAC, target temperature set.
      *
+     * The configArray is used to indicate the valid values for HVAC in Fahrenheit and Celsius.
+     * Android might use it in the HVAC app UI.
+     * The configArray is set as follows:
+     *      configArray[0] = [the lower bound of the supported temperature in Celsius] * 10.
+     *      configArray[1] = [the upper bound of the supported temperature in Celsius] * 10.
+     *      configArray[2] = [the increment in Celsius] * 10.
+     *      configArray[3] = [the lower bound of the supported temperature in Fahrenheit] * 10.
+     *      configArray[4] = [the upper bound of the supported temperature in Fahrenheit] * 10.
+     *      configArray[5] = [the increment in Fahrenheit] * 10.
+     * For example, if the vehicle supports temperature values as:
+     *      [16.0, 16.5, 17.0 ,..., 28.0] in Celsius
+     *      [60.5, 61.5, 62.5 ,..., 85.5] in Fahrenheit.
+     * The configArray should be configArray = {160, 280, 5, 605, 825, 10}.
+     *
+     * If the vehicle supports HVAC_TEMPERATURE_VALUE_SUGGESTION, the application can use
+     * that property to get the suggested value before setting HVAC_TEMPERATURE_SET. Otherwise,
+     * the application may choose the value in HVAC_TEMPERATURE_SET configArray by itself.
+     *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
      * @access VehiclePropertyAccess:READ_WRITE
      * @unit VehicleUnit:CELSIUS
@@ -1229,6 +1266,50 @@
         | VehiclePropertyType:BOOLEAN
         | VehicleArea:WINDOW),
 
+    /**
+     * Suggested values for setting HVAC temperature.
+     *
+     * Implement the property to help applications understand the closest supported temperature
+     * value in Celsius or Fahrenheit.
+     *
+     *      floatValues[0] = the requested value that an application wants to set a temperature to.
+     *      floatValues[1] = the unit for floatValues[0]. It should be one of
+     *                       {VehicleUnit:CELSIUS, VehicleUnit:FAHRENHEIT}.
+     *      floatValues[2] = the value OEMs suggested in CELSIUS. This value is not included
+     *                       in the request.
+     *      floatValues[3] = the value OEMs suggested in FAHRENHEIT. This value is not included
+     *                       in the request.
+     *
+     * An application calls set(VehiclePropValue propValue) with the requested value and unit for
+     * the value. OEMs need to return the suggested values in floatValues[2] and floatValues[3] by
+     * onPropertyEvent() callbacks.
+     *
+     * For example, when a user uses the voice assistant to set HVAC temperature to 66.2 in
+     * Fahrenheit.
+     * First, an application will set this property with the value
+     * [66.2, (float)VehicleUnit:FAHRENHEIT,0,0].
+     * If OEMs suggest to set 19.0 in Celsius or 66.5 in Fahrenheit for user's request, then VHAL
+     * must generate a callback with property value
+     * [66.2, (float)VehicleUnit:FAHRENHEIT, 19.0, 66.5]. After the voice assistant gets the
+     * callback, it will inform the user and set HVAC temperature to the suggested value.
+     *
+     * Another example, an application receives 21 Celsius as the current temperature value by
+     * querying HVC_TEMPERATURE_SET. But the application wants to know what value is displayed on
+     * the car's UI in Fahrenheit.
+     * For this, the application sets the property to [21, (float)VehicleUnit:CELSIUS, 0, 0]. If
+     * the suggested value by the OEM for 21 Celsius is 70 Fahrenheit, then VHAL must generate a
+     * callback with property value [21, (float)VehicleUnit:CELSIUS, 21.0, 70.0].
+     * In this case, the application can know that the value is 70.0 Fahrenheit in the car’s UI.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    HVAC_TEMPERATURE_VALUE_SUGGESTION = (
+        0x0515
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:FLOAT_VEC
+        | VehicleArea:GLOBAL),
+
    /**
      * Distance units for display
      *
@@ -1348,6 +1429,48 @@
         | VehicleArea:GLOBAL),
 
     /**
+     * Current date and time, encoded as Unix time (in milliseconds).
+     * This value denotes the number of milliseconds seconds that have
+     * elapsed since 1/1/1970 UTC.
+     *
+     * Reading this value will give you the system’s time. This can be
+     * useful to synchronize other vehicle systems (dash clock etc).
+     *
+     * Writing this value will update the ‘ExternalTimeSuggestion’
+     * value (if enabled). This value may be consumed by the “Time
+     * Detector Service”, if other sources do not have a higher
+     * priority. For information on how to adjust time source
+     * priorities see Time Detector Service documentation.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     * @unit VehicleUnit:MILLI_SECS
+     */
+    UNIX_TIME = (
+        0x0606
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:INT64
+        | VehicleArea:GLOBAL),
+
+    /**
+     * External encryption binding seed.
+     *
+     * This value is mixed with the local key storage encryption key.
+     * This property holds 16 bytes, and is expected to be persisted on an ECU separate from
+     * the IVI. The property is initially set by AAOS, who generates it using a CSRNG.
+     * AAOS will then read the property on subsequent boots. The binding seed is expected to be
+     * reliably persisted. Any loss of the seed results in a factory reset of the IVI.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    STORAGE_ENCRYPTION_BINDING_SEED = (
+        0x0607
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:BYTES
+        | VehicleArea:GLOBAL),
+
+    /**
      * Outside temperature
      *
      * @change_mode VehiclePropertyChangeMode:CONTINUOUS
@@ -3077,15 +3200,21 @@
     /**
      * Changes the state of the cluster display.
      *
+     * Bounds: the area to render the cluster Activity.
+     * Inset: the area which Activity should avoid from placing any important
+     *     information.
+     *
      * int32[0]: on/off: 0 - off, 1 - on, -1 - don't care
-     * int32[1]: width: positive number - actual width in pixels
-                        -1 - don't care (should set "don't care" both width and height)
-     * int32[2]: height: same format with 'width'
-     * int32[3]: Inset - left: positive number - actual left inset value in pixels
+     * int32[1]: Bounds - left: positive number - left position in pixels
+                                -1 - don't care (should set all Bounds fields)
+     * int32[2]: Bounds - top:    same format with 'left'
+     * int32[3]: Bounds - right:  same format with 'left'
+     * int32[4]: Bounds - bottom: same format with 'left'
+     * int32[5]: Inset - left: positive number - actual left inset value in pixels
                                -1 - don't care (should set "don't care" all Inset fields)
-     * int32[4]: Inset - top:    same format with 'left'
-     * int32[5]: Inset - right:  same format with 'left'
-     * int32[6]: Inset - bottom: same format with 'left'
+     * int32[6]: Inset - top:    same format with 'left'
+     * int32[7]: Inset - right:  same format with 'left'
+     * int32[8]: Inset - bottom: same format with 'left'
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
      * @access VehiclePropertyAccess:READ
@@ -3107,16 +3236,18 @@
      * match the state.
      *
      * int32[0]: on/off: 0 - off, 1 - on
-     * int32[1]: width
-     * int32[2]: height
-     * int32[3]: Inset - left
-     * int32[4]: Inset - top
-     * int32[5]: Inset - right
-     * int32[6]: Inset - bottom
-     * int32[7]: the type of ClusterUI in the fullscreen or main screen.
+     * int32[1]: Bounds - left
+     * int32[2]: Bounds - top
+     * int32[3]: Bounds - right
+     * int32[4]: Bounds - bottom
+     * int32[5]: Inset - left
+     * int32[6]: Inset - top
+     * int32[7]: Inset - right
+     * int32[8]: Inset - bottom
+     * int32[9]: the type of ClusterUI in the fullscreen or main screen.
      *    0 indicates ClusterHome.
      *    the other values are followed by OEM's definition.
-     * int32[8]: the type of ClusterUI in sub screen if the currently two UIs are shown.
+     * int32[10]: the type of ClusterUI in sub screen if the currently two UIs are shown.
      *    -1 indicates the area isn't used any more.
      * bytes: the array to represent the availability of ClusterUI.
      *     0 indicates non-available and 1 indicates available.
@@ -3159,12 +3290,72 @@
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
      * @access VehiclePropertyAccess:WRITE
      */
-     CLUSTER_NAVIGATION_STATE_LEGACY = (
+     CLUSTER_NAVIGATION_STATE = (
          0x0F38
          | VehiclePropertyGroup:SYSTEM
          | VehiclePropertyType:BYTES
          | VehicleArea:GLOBAL),
 
+    /**
+     * Electronic Toll Collection card type.
+     *
+     * This property indicates the type of ETC card in this vehicle.
+     * If the head unit is aware of an ETC card attached to the vehicle, this property should
+     * return the type of card attached; otherwise, this property should be UNAVAILABLE.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ
+     * @data_enum ElectronicTollCollectionCardType
+     */
+     ELECTRONIC_TOLL_COLLECTION_CARD_TYPE = (
+         0x0F39
+         | VehiclePropertyGroup:SYSTEM
+         | VehiclePropertyType:INT32
+         | VehicleArea:GLOBAL),
+
+    /**
+     * Electronic Toll Collection card status.
+     *
+     * This property indicates the status of ETC card in this vehicle.
+     * If the head unit is aware of an ETC card attached to the vehicle,
+     * ELECTRONIC_TOLL_COLLECTION_CARD_TYPE gives that status of the card; otherwise,
+     * this property should be UNAVAILABLE.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ
+     * @data_enum ElectronicTollCollectionCardStatus
+     */
+     ELECTRONIC_TOLL_COLLECTION_CARD_STATUS = (
+         0x0F3A
+         | VehiclePropertyGroup:SYSTEM
+         | VehiclePropertyType:INT32
+         | VehicleArea:GLOBAL),
+};
+
+/**
+ * Used by ELECTRONIC_TOLL_COLLECTION_CARD_TYPE.
+ */
+enum ElectronicTollCollectionCardType : int32_t {
+    // Type is unknown or not in the list below.
+    UNKNOWN = 0,
+    // A Japanese ETC card reader that does not support ETC 2.0.
+    JP_ELECTRONIC_TOLL_COLLECTION_CARD = 1,
+    // A Japanese ETC 2.0 card reader.
+    JP_ELECTRONIC_TOLL_COLLECTION_CARD_V2 = 2,
+};
+
+/**
+ * Used by ELECTRONIC_TOLL_COLLECTION_CARD_STATUS.
+ */
+enum ElectronicTollCollectionCardStatus : int32_t {
+    // Status could not be determined
+    UNKNOWN = 0,
+    // A valid ETC card is present
+    ELECTRONIC_TOLL_COLLECTION_CARD_VALID = 1,
+    // An ETC card is present, but it is expired or otherwise invalid
+    ELECTRONIC_TOLL_COLLECTION_CARD_INVALID = 2,
+    // No ETC card is inserted in the reader.
+    ELECTRONIC_TOLL_COLLECTION_CARD_NOT_INSERTED = 3,
 };
 
 /**
@@ -3623,6 +3814,7 @@
     US_GALLON           = 0x42,
     IMPERIAL_GALLON     = 0x43,
     NANO_SECS           = 0x50,
+    MILLI_SECS          = 0x51,
     SECS                = 0x53,
     YEAR                = 0x59,
 
diff --git a/automotive/vehicle/2.0/vts/functional/Android.bp b/automotive/vehicle/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..e64e942
--- /dev/null
+++ b/automotive/vehicle/2.0/vts/functional/Android.bp
@@ -0,0 +1,30 @@
+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: "VtsHalAutomotiveVehicleV2_0TargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+    ],
+    srcs: [
+        "VtsHalAutomotiveVehicleV2_0TargetTest.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libhidlbase",
+        "liblog",
+    ],
+    static_libs: [
+        "android.hardware.automotive.vehicle@2.0",
+    ],
+    test_suites: [
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/automotive/vehicle/2.0/vts/functional/VtsHalAutomotiveVehicleV2_0TargetTest.cpp b/automotive/vehicle/2.0/vts/functional/VtsHalAutomotiveVehicleV2_0TargetTest.cpp
new file mode 100644
index 0000000..7f1d4d1
--- /dev/null
+++ b/automotive/vehicle/2.0/vts/functional/VtsHalAutomotiveVehicleV2_0TargetTest.cpp
@@ -0,0 +1,247 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "VtsHalAutomotiveVehicle"
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+using namespace android::hardware::automotive::vehicle::V2_0;
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+
+constexpr auto kTimeout = std::chrono::milliseconds(500);
+constexpr auto kInvalidProp = 0x31600207;
+
+class VtsVehicleCallback : public IVehicleCallback {
+  private:
+    using MutexGuard = std::lock_guard<std::mutex>;
+    using HidlVecOfValues = hidl_vec<VehiclePropValue>;
+    std::mutex mLock;
+    std::condition_variable mEventCond;
+    std::vector<HidlVecOfValues> mReceivedEvents;
+
+  public:
+    Return<void> onPropertyEvent(const hidl_vec<VehiclePropValue>& values) override {
+        {
+            MutexGuard guard(mLock);
+            mReceivedEvents.push_back(values);
+        }
+        mEventCond.notify_one();
+        return Return<void>();
+    }
+
+    Return<void> onPropertySet(const VehiclePropValue& /* value */) override {
+        return Return<void>();
+    }
+    Return<void> onPropertySetError(StatusCode /* errorCode */, int32_t /* propId */,
+                                    int32_t /* areaId */) override {
+        return Return<void>();
+    }
+
+    bool waitForExpectedEvents(size_t expectedEvents) {
+        std::unique_lock<std::mutex> g(mLock);
+
+        if (expectedEvents == 0 && mReceivedEvents.size() == 0) {
+            return mEventCond.wait_for(g, kTimeout) == std::cv_status::timeout;
+        }
+
+        while (expectedEvents != mReceivedEvents.size()) {
+            if (mEventCond.wait_for(g, kTimeout) == std::cv_status::timeout) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    void reset() { mReceivedEvents.clear(); }
+};
+
+class VehicleHalHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mVehicle = IVehicle::getService(GetParam());
+        ASSERT_NE(mVehicle.get(), nullptr);
+    }
+    virtual void TearDown() override {}
+
+    sp<IVehicle> mVehicle;
+
+    bool isBooleanGlobalProp(int32_t property) {
+        return (property & (int)VehiclePropertyType::MASK) == (int)VehiclePropertyType::BOOLEAN &&
+               (property & (int)VehicleArea::MASK) == (int)VehicleArea::GLOBAL;
+    }
+
+    void invokeGet(int32_t property, int32_t areaId) {
+        VehiclePropValue requestedValue{};
+        requestedValue.prop = property;
+        requestedValue.areaId = areaId;
+
+        invokeGet(requestedValue);
+    }
+
+    void invokeGet(const VehiclePropValue& requestedPropValue) {
+        mActualValue = VehiclePropValue{};  // reset previous values
+
+        StatusCode refStatus;
+        VehiclePropValue refValue;
+        bool isCalled = false;
+        mVehicle->get(requestedPropValue,
+                      [&refStatus, &refValue, &isCalled](StatusCode status,
+                                                         const VehiclePropValue& value) {
+                          refStatus = status;
+                          refValue = value;
+                          isCalled = true;
+                      });
+        ASSERT_TRUE(isCalled) << "callback wasn't called for property: " << requestedPropValue.prop;
+
+        mActualValue = refValue;
+        mActualStatusCode = refStatus;
+    }
+
+    VehiclePropValue mActualValue;
+    StatusCode mActualStatusCode;
+};
+
+// Test getAllPropConfig() returns at least 4 property configs.
+TEST_P(VehicleHalHidlTest, getAllPropConfigs) {
+    ALOGD("VehicleHalHidlTest::getAllPropConfigs");
+    bool isCalled = false;
+    hidl_vec<VehiclePropConfig> propConfigs;
+    mVehicle->getAllPropConfigs([&isCalled, &propConfigs](const hidl_vec<VehiclePropConfig>& cfgs) {
+        propConfigs = cfgs;
+        isCalled = true;
+    });
+    ASSERT_TRUE(isCalled);
+    ASSERT_GE(propConfigs.size(), 4);
+}
+
+// Test getPropConfig() can query all properties listed in CDD.
+TEST_P(VehicleHalHidlTest, getPropConfigs) {
+    ALOGD("VehicleHalHidlTest::getPropConfigs");
+    // Check the properties listed in CDD
+    hidl_vec<int32_t> properties = {
+            (int)VehicleProperty::GEAR_SELECTION, (int)VehicleProperty::NIGHT_MODE,
+            (int)VehicleProperty::PARKING_BRAKE_ON, (int)VehicleProperty::PERF_VEHICLE_SPEED};
+    bool isCalled = false;
+    mVehicle->getPropConfigs(
+            properties, [&isCalled](StatusCode status, const hidl_vec<VehiclePropConfig>& cfgs) {
+                ASSERT_EQ(StatusCode::OK, status);
+                ASSERT_EQ(4u, cfgs.size());
+                isCalled = true;
+            });
+    ASSERT_TRUE(isCalled);
+}
+
+// Test getPropConfig() with an invalid propertyId returns an error code.
+TEST_P(VehicleHalHidlTest, getPropConfigsWithInvalidProp) {
+    ALOGD("VehicleHalHidlTest::getPropConfigsWithInvalidProp");
+    hidl_vec<int32_t> properties = {kInvalidProp};
+    bool isCalled = false;
+    mVehicle->getPropConfigs(
+            properties, [&isCalled](StatusCode status, const hidl_vec<VehiclePropConfig>& cfgs) {
+                ASSERT_NE(StatusCode::OK, status);
+                ASSERT_EQ(0, cfgs.size());
+                isCalled = true;
+            });
+    ASSERT_TRUE(isCalled);
+}
+
+// Test get() return current value for properties.
+TEST_P(VehicleHalHidlTest, get) {
+    ALOGD("VehicleHalHidlTest::get");
+    invokeGet((int)VehicleProperty::PERF_VEHICLE_SPEED, 0);
+    ASSERT_EQ(StatusCode::OK, mActualStatusCode);
+}
+
+// Test get() with an invalid propertyId return an error codes.
+TEST_P(VehicleHalHidlTest, getInvalidProp) {
+    ALOGD("VehicleHalHidlTest::getInvalidProp");
+
+    invokeGet(kInvalidProp, 0);
+    ASSERT_NE(StatusCode::OK, mActualStatusCode);
+}
+
+// Test set() on read_write properties.
+TEST_P(VehicleHalHidlTest, setProp) {
+    ALOGD("VehicleHalHidlTest::setProp");
+    hidl_vec<VehiclePropConfig> propConfigs;
+    mVehicle->getAllPropConfigs(
+            [&propConfigs](const hidl_vec<VehiclePropConfig>& cfgs) { propConfigs = cfgs; });
+    for (const VehiclePropConfig& cfg : propConfigs) {
+        // test on boolean and writable property
+        if (cfg.access == VehiclePropertyAccess::READ_WRITE && isBooleanGlobalProp(cfg.prop)) {
+            invokeGet(cfg.prop, 0);
+            int setValue = mActualValue.value.int32Values[0] == 1 ? 0 : 1;
+            VehiclePropValue propToSet = mActualValue;
+            propToSet.value.int32Values[0] = setValue;
+            ASSERT_EQ(StatusCode::OK, mVehicle->set(propToSet));
+            // check set success
+            invokeGet(cfg.prop, 0);
+            ASSERT_EQ(StatusCode::OK, mActualStatusCode);
+            ASSERT_EQ(setValue, mActualValue.value.int32Values[0]);
+        }
+    }
+}
+
+// Test set() on an read_only property.
+TEST_P(VehicleHalHidlTest, setNotWritableProp) {
+    ALOGD("VehicleHalHidlTest::setNotWritableProp");
+    invokeGet(static_cast<int>(VehicleProperty::PERF_VEHICLE_SPEED), 0);
+    ASSERT_EQ(StatusCode::OK, mActualStatusCode);
+    VehiclePropValue vehicleSpeed = mActualValue;
+
+    ASSERT_EQ(StatusCode::ACCESS_DENIED, mVehicle->set(vehicleSpeed));
+}
+
+// Test subscribe() and unsubscribe().
+TEST_P(VehicleHalHidlTest, subscribeAndUnsubscribe) {
+    ALOGD("VehicleHalHidlTest::subscribeAndUnsubscribe");
+    const auto prop = static_cast<int>(VehicleProperty::PERF_VEHICLE_SPEED);
+    sp<VtsVehicleCallback> cb = new VtsVehicleCallback();
+
+    hidl_vec<SubscribeOptions> options = {
+            SubscribeOptions{.propId = prop, 100.0, .flags = SubscribeFlags::EVENTS_FROM_CAR}};
+
+    ASSERT_EQ(StatusCode::OK, mVehicle->subscribe(cb, options));
+    ASSERT_TRUE(cb->waitForExpectedEvents(10));
+
+    ASSERT_EQ(StatusCode::OK, mVehicle->unsubscribe(cb, prop));
+    cb->reset();
+    ASSERT_FALSE(cb->waitForExpectedEvents(10));
+}
+
+// Test subscribe() with an invalid property.
+TEST_P(VehicleHalHidlTest, subscribeInvalidProp) {
+    ALOGD("VehicleHalHidlTest::subscribeInvalidProp");
+
+    sp<VtsVehicleCallback> cb = new VtsVehicleCallback();
+
+    hidl_vec<SubscribeOptions> options = {SubscribeOptions{
+            .propId = kInvalidProp, 10.0, .flags = SubscribeFlags::EVENTS_FROM_CAR}};
+
+    ASSERT_NE(StatusCode::OK, mVehicle->subscribe(cb, options));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, VehicleHalHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVehicle::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Feature.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Feature.aidl
index a8faf06..1875b97 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Feature.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/Feature.aidl
@@ -34,7 +34,7 @@
 package android.hardware.biometrics.face;
 @Backing(type="byte") @VintfStability
 enum Feature {
-  WAVE_ATTENTION_REQUIREMENT = 0,
-  WAVE_DIVERSE_POSES_REQUIREMENT = 1,
+  REQUIRE_ATTENTION = 0,
+  REQUIRE_DIVERSE_POSES = 1,
   DEBUG = 2,
 }
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl
index 205429b..1ee3caf 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl
@@ -34,17 +34,17 @@
 package android.hardware.biometrics.face;
 @VintfStability
 interface ISession {
-  void generateChallenge(in int cookie);
-  void revokeChallenge(in int cookie, in long challenge);
-  android.hardware.biometrics.common.ICancellationSignal enroll(in int cookie, in android.hardware.keymaster.HardwareAuthToken hat, in android.hardware.biometrics.face.EnrollmentType type, in android.hardware.biometrics.face.Feature[] features, in android.hardware.common.NativeHandle previewSurface);
-  android.hardware.biometrics.common.ICancellationSignal authenticate(in int cookie, in long operationId);
-  android.hardware.biometrics.common.ICancellationSignal detectInteraction(in int cookie);
-  void enumerateEnrollments(in int cookie);
-  void removeEnrollments(in int cookie, in int[] enrollmentIds);
-  void getFeatures(in int cookie, in int enrollmentId);
-  void setFeature(in int cookie, in android.hardware.keymaster.HardwareAuthToken hat, in int enrollmentId, in android.hardware.biometrics.face.Feature feature, boolean enabled);
-  void getAuthenticatorId(in int cookie);
-  void invalidateAuthenticatorId(in int cookie);
-  void resetLockout(in int cookie, in android.hardware.keymaster.HardwareAuthToken hat);
-  void close(in int cookie);
+  void generateChallenge();
+  void revokeChallenge(in long challenge);
+  android.hardware.biometrics.common.ICancellationSignal enroll(in android.hardware.keymaster.HardwareAuthToken hat, in android.hardware.biometrics.face.EnrollmentType type, in android.hardware.biometrics.face.Feature[] features, in android.hardware.common.NativeHandle previewSurface);
+  android.hardware.biometrics.common.ICancellationSignal authenticate(in long operationId);
+  android.hardware.biometrics.common.ICancellationSignal detectInteraction();
+  void enumerateEnrollments();
+  void removeEnrollments(in int[] enrollmentIds);
+  void getFeatures();
+  void setFeature(in android.hardware.keymaster.HardwareAuthToken hat, in android.hardware.biometrics.face.Feature feature, boolean enabled);
+  void getAuthenticatorId();
+  void invalidateAuthenticatorId();
+  void resetLockout(in android.hardware.keymaster.HardwareAuthToken hat);
+  void close();
 }
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISessionCallback.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISessionCallback.aidl
index b0bfa30..bbace29 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISessionCallback.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISessionCallback.aidl
@@ -34,7 +34,6 @@
 package android.hardware.biometrics.face;
 @VintfStability
 interface ISessionCallback {
-  void onStateChanged(in int cookie, in android.hardware.biometrics.face.SessionState state);
   void onChallengeGenerated(in long challenge);
   void onChallengeRevoked(in long challenge);
   void onAuthenticationFrame(in android.hardware.biometrics.face.AuthenticationFrame frame);
@@ -48,8 +47,8 @@
   void onLockoutCleared();
   void onInteractionDetected();
   void onEnrollmentsEnumerated(in int[] enrollmentIds);
-  void onFeaturesRetrieved(in android.hardware.biometrics.face.Feature[] features, in int enrollmentId);
-  void onFeatureSet(in int enrollmentId, android.hardware.biometrics.face.Feature feature);
+  void onFeaturesRetrieved(in android.hardware.biometrics.face.Feature[] features);
+  void onFeatureSet(android.hardware.biometrics.face.Feature feature);
   void onEnrollmentsRemoved(in int[] enrollmentIds);
   void onAuthenticatorIdRetrieved(in long authenticatorId);
   void onAuthenticatorIdInvalidated(in long newAuthenticatorId);
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/Feature.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/Feature.aidl
index b88050a..bff1a02 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/Feature.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/Feature.aidl
@@ -20,20 +20,19 @@
 @Backing(type="byte")
 enum Feature {
     /**
-     * Do not require the user to look at the device during enrollment and authentication. Note
-     * this is to accommodate people who have limited vision.
+     * Require the user to look at the device during enrollment and authentication. This feature
+     * can be disabled to accommodate people who have limited vision.
      */
-    WAVE_ATTENTION_REQUIREMENT,
+    REQUIRE_ATTENTION,
 
     /**
-     * Do not require a diverse set of poses during enrollment. This is to accommodate people with
-     * limited mobility.
+     * Require a diverse set of poses during enrollment. This feature can be disabled to accommodate
+     * people with limited mobility.
      */
-    WAVE_DIVERSE_POSES_REQUIREMENT,
+    REQUIRE_DIVERSE_POSES,
 
     /**
      * Enable debugging functionality.
      */
     DEBUG,
 }
-
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
index 66c7c38..12911e3 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
@@ -23,11 +23,25 @@
 import android.hardware.keymaster.HardwareAuthToken;
 
 /**
- * A session is a collection of immutable state (sensorId, userId), mutable state (SessionState),
- * methods available for the framework to call, and a callback (ISessionCallback) to notify the
- * framework about the events and results. A session is used to establish communication between
- * the framework and the HAL.
+ * Operations that can be performed for unique sessions retrieved via IFace#createSession.
+ * Operations defined within this interface can be divided into the following categories:
+ * 1) Cancellable operations. These are usually the operations that can execute for several
+ *     minutes. To allow for cancellation, they return an instance of ICancellationSignal that
+ *     lets the framework cancel them by calling ICancellationSignal#cancel. If such an operation
+ *     is cancelled, it must notify the framework by calling ISessionCallback#onError with
+ *     Error::CANCELED.
+ * 2) Non-cancellable operations. Such operations cannot be cancelled once started.
+ *
+ * The lifecycle of an operation ends when one of its terminal callbacks is called. For example,
+ * ISession#authenticate is considered completed when any of the following callbacks is called:
+ * ISessionCallback#onError, ISessionCallback#onAuthenticationSucceeded,
+ * ISessionCallback#onAuthenticationFailed.
+ *
+ * ISession only supports execution of one operation at a time, regardless of whether it's
+ * cancellable or not. The framework must wait for a corresponding callback indicating the end of
+ * the current operation before a new operation can be started.
  */
+
 @VintfStability
 interface ISession {
     /**
@@ -55,7 +69,7 @@
      *
      * Note that this interface allows multiple in-flight challenges. Invoking generateChallenge
      * twice does not invalidate the first challenge. The challenge is invalidated only when:
-     *   1) Its lifespan exceeds the HAL's internal challenge timeout
+     *   1) Its lifespan exceeds the challenge timeout defined in the TEE.
      *   2) IFingerprint#revokeChallenge is invoked
      *
      * For example, the following is a possible table of valid challenges:
@@ -68,9 +82,8 @@
      * | 0        | 10     | <Time4>    | <Random4> |
      * ----------------------------------------------
      *
-     * @param cookie A unique number identifying this operation
      */
-    void generateChallenge(in int cookie);
+    void generateChallenge();
 
     /**
      * revokeChallenge:
@@ -79,10 +92,9 @@
      * parameters is requested, the implementation must still notify the framework using the
      * provided callback.
      *
-     * @param cookie A unique number identifying this operation
      * @param challenge Challenge that should be revoked.
      */
-    void revokeChallenge(in int cookie, in long challenge);
+    void revokeChallenge(in long challenge);
 
     /**
      * getEnrollmentConfig:
@@ -101,19 +113,13 @@
      *
      * A request to add a face enrollment.
      *
-     * Once the HAL is able to start processing the enrollment request, it must notify the framework
-     * via ISessionCallback#onStateChanged with SessionState::ENROLLING.
-     *
      * At any point during enrollment, if a non-recoverable error occurs, the HAL must notify the
-     * framework via ISessionCallback#onError with the applicable enrollment-specific error, and
-     * then send ISessionCallback#onStateChanged(cookie, SessionState::IDLING) if no subsequent
-     * operation is in the queue.
+     * framework via ISessionCallback#onError with the applicable enrollment-specific error.
      *
      * Before capturing face data, the implementation must first verify the authenticity and
      * integrity of the provided HardwareAuthToken. In addition, it must check that the challenge
      * within the provided HardwareAuthToken is valid. See ISession#generateChallenge. If any of
-     * the above checks fail, the framework must be notified via ISessionCallback#onError and the
-     * HAL must notify the framework when it returns to the idle state. See
+     * the above checks fail, the framework must be notified using ISessionCallback#onError with
      * Error::UNABLE_TO_PROCESS.
      *
      * During enrollment, the implementation may notify the framework via
@@ -121,15 +127,12 @@
      * can be invoked multiple times if necessary. Similarly, the framework may be notified of
      * enrollment progress changes via ISessionCallback#onEnrollmentProgress. Once the framework is
      * notified that there are 0 "remaining" steps, the framework may cache the "enrollmentId". See
-     * ISessionCallback#onEnrollmentProgress for more info. The HAL must notify the framework once
-     * it returns to the idle state.
+     * ISessionCallback#onEnrollmentProgress for more info.
      *
-     * When a finger is successfully added and before the framework is notified of remaining=0, the
-     * implementation MUST update and associate this (sensorId, userId) pair with a new new
+     * When a face is successfully added and before the framework is notified of remaining=0, the
+     * implementation MUST update and associate this (sensorId, userId) pair with a new
      * entropy-encoded random identifier. See ISession#getAuthenticatorId for more information.
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path. The
-     *               client must guarantee that it is unique per ISession.
      * @param hat See above documentation.
      * @param enrollmentType See the EnrollmentType enum.
      * @param features See the Feature enum.
@@ -139,7 +142,7 @@
      * @return ICancellationSignal An object that can be used by the framework to cancel this
      * operation.
      */
-    ICancellationSignal enroll(in int cookie, in HardwareAuthToken hat, in EnrollmentType type,
+    ICancellationSignal enroll(in HardwareAuthToken hat, in EnrollmentType type,
             in Feature[] features, in NativeHandle previewSurface);
 
     /**
@@ -147,13 +150,8 @@
      *
      * A request to start looking for faces to authenticate.
      *
-     * Once the HAL is able to start processing the authentication request, it must notify framework
-     * via ISessionCallback#onStateChanged with SessionState::AUTHENTICATING.
-     *
      * At any point during authentication, if a non-recoverable error occurs, the HAL must notify
-     * the framework via ISessionCallback#onError with the applicable authentication-specific error,
-     * and then send ISessionCallback#onStateChanged(cookie, SessionState::IDLING) if no
-     * subsequent operation is in the queue.
+     * the framework via ISessionCallback#onError with the applicable authentication-specific error.
      *
      * During authentication, the implementation may notify the framework via
      * ISessionCallback#onAcquired with messages that may be used to guide the user. This callback
@@ -175,8 +173,6 @@
      * must be set with the operationId passed in during #authenticate. If the sensor is NOT
      * SensorStrength::STRONG, the HardwareAuthToken MUST be null.
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path. The
-     *               client must guarantee that it is unique per ISession.
      * @param operationId For sensors configured as SensorStrength::STRONG, this must be used ONLY
      *                    upon successful authentication and wrapped in the HardwareAuthToken's
      *                    "challenge" field and sent to the framework via
@@ -190,7 +186,7 @@
      * @return ICancellationSignal An object that can be used by the framework to cancel this
      * operation.
      */
-    ICancellationSignal authenticate(in int cookie, in long operationId);
+    ICancellationSignal authenticate(in long operationId);
 
     /**
      * detectInteraction:
@@ -199,17 +195,12 @@
      * SensorProps#supportsDetectInteraction is true. If invoked on implementations that do not
      * support this functionality, the HAL must respond with ISession#onError(UNABLE_TO_PROCESS, 0).
      *
-     * Once the HAL is able to start processing this request, it must notify the framework via
-     * ISessionCallback#onStateChanged with SessionState::DETECTING_INTERACTION.
-     *
      * The framework will use this method in cases where determing user presence is required, but
      * identifying/authentication is not. For example, when the device is encrypted (first boot) or
      * in lockdown mode.
      *
      * At any point during detectInteraction, if a non-recoverable error occurs, the HAL must notify
-     * the framework via ISessionCallback#onError with the applicable error, and then send
-     * ISessionCallback#onStateChanged(cookie, SessionState::IDLING) if no subsequent operation is
-     * in the queue.
+     * the framework via ISessionCallback#onError with the applicable error.
      *
      * The implementation must only check for a face-like image was detected (e.g. to
      * minimize interactions due to non-face objects), and the lockout counter must not
@@ -222,17 +213,15 @@
      * 1) Any face is detected and the framework is notified via
      *    ISessionCallback#onInteractiondetected
      * 2) The operation was cancelled by the framework (see ICancellationSignal)
-     * 3) The HAL ends the operation, for example when a subsequent operation pre-empts this one.
+     * 3) An error occurred, for example ERROR::TIMEOUT
      *
      * Note that if the operation is canceled, the implementation must notify the framework via
      * ISessionCallback#onError with Error::CANCELED.
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path.
-     *               The framework will guarantee that it is unique per ISession.
      * @return ICancellationSignal An object that can be used by the framework to cancel this
      * operation.
      */
-    ICancellationSignal detectInteraction(in int cookie);
+    ICancellationSignal detectInteraction();
 
     /*
      * enumerateEnrollments:
@@ -240,80 +229,54 @@
      * A request to enumerate (list) the enrollments for this (sensorId, userId) pair. The
      * framework typically uses this to ensure that its cache is in sync with the HAL.
      *
-     * Once the HAL is able to start processing this request, it must notify the framework via
-     * ISessionCallback#onStateChanged with SessionState::ENUMERATING_ENROLLMENTS.
-     *
      * The implementation must then notify the framework with a list of enrollments applicable
      * for the current session via ISessionCallback#onEnrollmentsEnumerated.
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path.
-     *               The framework will guarantee that it is unique per ISession.
      */
-    void enumerateEnrollments(in int cookie);
+    void enumerateEnrollments();
 
     /**
      * removeEnrollments:
      *
      * A request to remove the enrollments for this (sensorId, userId) pair.
      *
-     * Once the HAL is able to start processing this request, it must notify the framework via
-     * ISessionCallback#onStateChanged with SessionState::REMOVING_ENROLLMENTS.
-     *
      * After removing the enrollmentIds from everywhere necessary (filesystem, secure subsystems,
      * etc), the implementation must notify the framework via ISessionCallback#onEnrollmentsRemoved.
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path.
-     *               The framework will guarantee that it is unique per ISession.
      */
-    void removeEnrollments(in int cookie, in int[] enrollmentIds);
+    void removeEnrollments(in int[] enrollmentIds);
 
     /**
      * getFeatures:
      *
-     * Returns a list of currently enabled features for the provided enrollmentId.
+     * Returns a list of currently enabled features for this (sensorId, userId) pair.
      *
-     * If the enrollmentId is invalid, the HAL must invoke ISessionCallback#onError with
-     * Error::UNABLE_TO_PROCESS and return to SessionState::IDLING if no subsequent work is in the
-     * queue.
-     *
-     * Once the HAL is able to start processing this request, it must notify the framework by using
-     * ISessionCallback#onStateChanged with SessionState::GETTING_FEATURES.
+     * If the user is not enrolled, the HAL must invoke ISessionCallback#onError with
+     * Error::UNABLE_TO_PROCESS.
      *
      * The HAL must notify the framework about the result by calling
      * ISessionCallback#onFeaturesRetrieved.
-     *
-     * @param cookie An identifier used to track subsystem operations related to this call path. The
-     *               client must guarantee that it is unique per ISession.
-     * @param enrollmentId the ID of the enrollment for which the features are requested.
      */
-    void getFeatures(in int cookie, in int enrollmentId);
+    void getFeatures();
 
     /**
      * setFeature:
      *
-     * Enables or disables a feature for the given enrollmentId. Because certain features may
+     * Enables or disables a feature for this (sensorId, userId) pair. Because certain features may
      * decrease security, the user must enter their password before this method is invoked
      * (see @param hat). The HAL must verify the hat before changing any feature state.
      *
-     * If either the hat or enrollmentId is invalid, the HAL must invoke ISessionCallback#onError
-     * with Error::UNABLE_TO_PROCESS and return to SessionState::IDLING if no subsequent work is in
-     * the queue.
-     *
-     * Once the HAL is able to start processing this request, it must notify the framework by using
-     * ISessionCallback#onStateChanged with SessionState::SETTING_FEATURE.
+     * If the hat is invalid or if the user is not enrolled, the HAL must invoke
+     * ISessionCallback#onError with Error::UNABLE_TO_PROCESS.
      *
      * After the feature is successfully set, the HAL must notify the framework by calling
      * ISessionCallback#onFeatureSet.
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path. The
-     *               client must guarantee that it is unique per ISession.
      * @param hat HardwareAuthToken See above documentation.
-     * @param enrollmentId the ID of the enrollment for which the feature update is requested.
      * @param feature The feature to be enabled or disabled.
      * @param enabled Whether the provided features should be enabled or disabled.
      */
-    void setFeature(in int cookie, in HardwareAuthToken hat, in int enrollmentId,
-            in Feature feature, boolean enabled);
+    void setFeature(in HardwareAuthToken hat, in Feature feature, boolean enabled);
 
     /**
      * getAuthenticatorId:
@@ -341,10 +304,8 @@
      *   3) MUST not change if a face is deleted.
      *   4) MUST be an entropy-encoded random number
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path. The
-     *               client must guarantee that it is unique per ISession.
      */
-    void getAuthenticatorId(in int cookie);
+    void getAuthenticatorId();
 
     /**
      * invalidateAuthenticatorId:
@@ -368,10 +329,8 @@
      * for more details). As such, the framework would coordinate invalidation across multiple
      * biometric HALs as necessary.
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path. The
-     *               client must guarantee that it is unique per ISession.
      */
-    void invalidateAuthenticatorId(in int cookie);
+    void invalidateAuthenticatorId();
 
     /**
      * resetLockout:
@@ -382,8 +341,7 @@
      *   2) Verify that the timestamp provided within the HAT is relatively recent (e.g. on the
      *      order of minutes, not hours).
      * If either of the checks fail, the HAL must invoke ISessionCallback#onError with
-     * Error::UNABLE_TO_PROCESS and return to SessionState::IDLING if no subsequent work is in the
-     * queue.
+     * Error::UNABLE_TO_PROCESS.
      *
      * Upon successful verification, the HAL must clear the lockout counter and notify the framework
      * via ISessionCallback#onLockoutCleared.
@@ -414,27 +372,20 @@
      * See the Android CDD section 7.3.10 for the full set of lockout and rate-limiting
      * requirements.
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path. The
-     *               client must guarantee that it is unique per ISession.
      * @param hat HardwareAuthToken See above documentation.
      */
-    void resetLockout(in int cookie, in HardwareAuthToken hat);
+    void resetLockout(in HardwareAuthToken hat);
 
     /*
      * Close this session and allow the HAL to release the resources associated with this session.
      *
-     * A session can only be closed when it's in SessionState::IDLING. Closing a session will
-     * result in a ISessionCallback#onStateChanged call with SessionState::CLOSED.
-     *
-     * If a session is unresponsive or stuck in a state other than SessionState::CLOSED,
-     * IFace#reset could be used as a last resort to terminate the session and recover the HAL
-     * from a bad state.
+     * A session can only be closed when the HAL is idling, i.e. not performing any operations.
+     * If the HAL is busy performing a cancellable operation, the operation must be explicitly
+     * cancelled with a call to ICancellationSignal#cancel before the session can be closed.
      *
      * All sessions must be explicitly closed. Calling IFace#createSession while there is an active
      * session is considered an error.
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path. The
-     *               client must guarantee that it is unique per ISession.
      */
-    void close(in int cookie);
+    void close();
 }
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl
index c1aa3fc..23570bd 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl
@@ -21,17 +21,11 @@
 import android.hardware.biometrics.face.EnrollmentFrame;
 import android.hardware.biometrics.face.Error;
 import android.hardware.biometrics.face.Feature;
-import android.hardware.biometrics.face.SessionState;
 import android.hardware.keymaster.HardwareAuthToken;
 
 @VintfStability
 interface ISessionCallback {
     /**
-     * Used to notify the framework of session state changes. See ISession for more information.
-     */
-    void onStateChanged(in int cookie, in SessionState state);
-
-    /**
      * Notifies the framework when a challenge is successfully generated.
      */
     void onChallengeGenerated(in long challenge);
@@ -42,9 +36,9 @@
     void onChallengeRevoked(in long challenge);
 
     /**
-     * This method must only be used to notify the framework during the following states:
-     *   1) SessionState::AUTHENTICATING
-     *   2) SessionState::DETECTING_INTERACTION
+     * This method must only be used to notify the framework during the following operations:
+     *   1) ISession#authenticate
+     *   2) ISession#detectInteraction
      *
      * These messages may be used to provide user guidance multiple times if necessary per
      * operation.
@@ -54,8 +48,8 @@
     void onAuthenticationFrame(in AuthenticationFrame frame);
 
     /**
-     * This method must only be used to notify the framework during the SessionState::ENROLLING
-     * state.
+     * This method must only be used to notify the framework during the ISession#enroll
+     * operation.
      *
      * These messages may be used to provide user guidance multiple times if necessary per
      * operation.
@@ -65,18 +59,18 @@
     void onEnrollmentFrame(in EnrollmentFrame frame);
 
     /**
-     * This method must only be used to notify the framework during the following states:
-     *   1) SessionState::ENROLLING
-     *   2) SessionState::AUTHENTICATING
-     *   3) SessionState::DETECTING_INTERACTION
-     *   4) SessionState::INVALIDATING_AUTHENTICATOR_ID
-     *   5) SessionState::RESETTING_LOCKOUT
+     * This method must only be used to notify the framework during the following operations:
+     *   1) ISession#enroll
+     *   2) ISession#authenticate
+     *   3) ISession#detectInteraction
+     *   4) ISession#invalidateAuthenticatorId
+     *   5) ISession#resetLockout
      *
      * These messages may be used to notify the framework or user that a non-recoverable error
      * has occurred. The operation is finished, and the HAL must proceed with the next operation
-     * or return to SessionState::IDLING if the queue is empty.
+     * or return to the idling state.
      *
-     * Note that cancellation (see common::ICancellationSignal) and preemption most be followed with
+     * Note that cancellation (see common::ICancellationSignal) and preemption must be followed with
      * an Error::CANCELED message.
      *
      * @param error See the Error enum.
@@ -88,8 +82,7 @@
     void onError(in Error error, in int vendorCode);
 
     /**
-     * This method must only be used to notify the framework during the following state:
-     *   1) SessionState::ENROLLING
+     * This method must only be used to notify the framework during the ISession#enroll operation.
      *
      * @param enrollmentId Unique stable identifier for the enrollment that's being added by this
      *                     ISession#enroll invocation.
@@ -98,7 +91,7 @@
     void onEnrollmentProgress(in int enrollmentId, int remaining);
 
     /**
-     * This method must only be used to notify the framework during SessionState::AUTHENTICATING.
+     * This method must only be used to notify the framework during ISession#authenticate.
      *
      * Used to notify the framework about a successful authentication. This ends the authentication
      * lifecycle.
@@ -112,7 +105,7 @@
     void onAuthenticationSucceeded(in int enrollmentId, in HardwareAuthToken hat);
 
     /**
-     * This method must only be used to notify the framework during SessionState::AUTHENTICATING.
+     * This method must only be used to notify the framework during ISession#authenticate.
      *
      * Used to notify the framework about a failed authentication. This ends the authentication
      * lifecycle.
@@ -120,7 +113,7 @@
     void onAuthenticationFailed();
 
     /**
-     * This method must only be used to notify the framework during SessionState::AUTHENTICATING.
+     * This method must only be used to notify the framework during ISession#authenticate.
      *
      * Authentication is locked out due to too many unsuccessful attempts. This is a rate-limiting
      * lockout, and authentication can be restarted after a period of time. See
@@ -133,7 +126,7 @@
     void onLockoutTimed(in long durationMillis);
 
     /**
-     * This method must only be used to notify the framework during SessionState::AUTHENTICATING.
+     * This method must only be used to notify the framework during ISession#authenticate.
      *
      * Authentication is disabled until the user unlocks with their device credential
      * (PIN/Pattern/Password). See ISession#resetLockout.
@@ -160,7 +153,7 @@
 
     /**
      * This method must only be used to notify the framework during
-     * SessionState::DETECTING_INTERACTION
+     * ISession#detectInteraction
      *
      * Notifies the framework that user interaction occurred. See ISession#detectInteraction.
      */
@@ -168,7 +161,7 @@
 
     /**
      * This method must only be used to notify the framework during
-     * SessionState::ENUMERATING_ENROLLMENTS.
+     * ISession#enumerateEnrollments.
      *
      * Notifies the framework of the current enrollments. See ISession#enumerateEnrollments.
      *
@@ -177,28 +170,27 @@
     void onEnrollmentsEnumerated(in int[] enrollmentIds);
 
     /**
-     * This method must only be used to notify the framework during SessionState::GETTING_FEATURES.
+     * This method must only be used to notify the framework during ISession#getFeatures.
      *
-     * Provides a list of features that are currently enabled for the given enrollmentId.
+     * Provides a list of features that are currently enabled for the session's (userId, sensorId)
+     * pair.
      *
      * @param features A list of currently enabled features. See the Feature enum.
-     * @param enrollmentId The enrollment for which the features were requested.
      */
-    void onFeaturesRetrieved(in Feature[] features, in int enrollmentId);
+    void onFeaturesRetrieved(in Feature[] features);
 
     /**
-     * This method must only be used to notify the framework during SessionState::SETTING_FEATURE.
+     * This method must only be used to notify the framework during ISession#setFeature.
      *
      * Notifies the framework that ISession#setFeature has completed.
      *
-     * @param enrollmentId The enrollment for which a feature was set.
      * @param feature The feature that was set.
      */
-    void onFeatureSet(in int enrollmentId, Feature feature);
+    void onFeatureSet(Feature feature);
 
     /**
      * This method must only be used to notify the framework during
-     * SessionState::REMOVING_ENROLLMENTS.
+     * ISession#removeEnrollments.
      *
      * Notifies the framework that the specified enrollments are removed.
      *
@@ -208,7 +200,7 @@
 
     /**
      * This method must only be used to notify the framework during
-     * SessionState::GETTING_AUTHENTICATOR_ID.
+     * ISession#getAuthenticatorId.
      *
      * Notifies the framework with the authenticatorId corresponding to this session's
      * (userId, sensorId) pair.
@@ -219,7 +211,7 @@
 
     /**
      * This method must only be used to notify the framework during
-     * SessionState::INVALIDATING_AUTHENTICATOR_ID.
+     * ISession#invalidateAuthenticatorId.
      *
      * See ISession#invalidateAuthenticatorId for more information.
      *
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/SessionState.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/SessionState.aidl
deleted file mode 100644
index afde4eb..0000000
--- a/biometrics/face/aidl/android/hardware/biometrics/face/SessionState.aidl
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.biometrics.face;
-
-@VintfStability
-@Backing(type="byte")
-enum SessionState {
-    /**
-     * The HAL is not processing any session requests.
-     */
-    IDLING,
-
-    /**
-     * The session has been closed by the client.
-     */
-    CLOSED,
-
-    /**
-     * The HAL is processing the ISession#generateChallenge request.
-     */
-    GENERATING_CHALLENGE,
-
-    /**
-     * The HAL is processing the ISession#revokeChallenge request.
-     */
-    REVOKING_CHALLENGE,
-
-    /**
-     * The HAL is processing the ISession#enroll request.
-     */
-    ENROLLING,
-
-    /**
-     * The HAL is processing the ISession#authenticate request.
-     */
-    AUTHENTICATING,
-
-    /**
-     * The HAL is processing the ISession#detectInteraction request.
-     */
-    DETECTING_INTERACTION,
-
-    /**
-     * The HAL is processing the ISession#enumerateEnrollments request.
-     */
-    ENUMERATING_ENROLLMENTS,
-
-    /**
-     * The HAL is processing the ISession#removeEnrollments request.
-     */
-    REMOVING_ENROLLMENTS,
-
-    /**
-     * The HAL is processing the ISession#getFeatures request.
-     */
-    GETTING_FEATURES,
-
-    /**
-     * The HAL is processing the ISession#setFeature request.
-     */
-    SETTING_FEATURE,
-
-    /**
-     * The HAL is processing the ISession#getAuthenticatorId request.
-     */
-    GETTING_AUTHENTICATOR_ID,
-
-    /**
-     * The HAL is processing the ISession#invalidateAuthenticatorId request.
-     */
-    INVALIDATING_AUTHENTICATOR_ID,
-
-    /**
-     * The HAL is processing the ISession#resetLockout request.
-     */
-    RESETTING_LOCKOUT
-}
diff --git a/biometrics/face/aidl/default/Session.cpp b/biometrics/face/aidl/default/Session.cpp
index ce6c557..4438d35 100644
--- a/biometrics/face/aidl/default/Session.cpp
+++ b/biometrics/face/aidl/default/Session.cpp
@@ -30,119 +30,104 @@
 
     ndk::ScopedAStatus cancel() override {
         cb_->onError(Error::CANCELED, 0 /* vendorCode */);
-        cb_->onStateChanged(0, SessionState::IDLING);
         return ndk::ScopedAStatus::ok();
     }
 };
 
 Session::Session(std::shared_ptr<ISessionCallback> cb) : cb_(std::move(cb)) {}
 
-ndk::ScopedAStatus Session::generateChallenge(int32_t /*cookie*/) {
+ndk::ScopedAStatus Session::generateChallenge() {
     LOG(INFO) << "generateChallenge";
     if (cb_) {
-        cb_->onStateChanged(0, SessionState::GENERATING_CHALLENGE);
         cb_->onChallengeGenerated(0);
-        cb_->onStateChanged(0, SessionState::IDLING);
     }
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::revokeChallenge(int32_t /*cookie*/, int64_t challenge) {
+ndk::ScopedAStatus Session::revokeChallenge(int64_t challenge) {
     LOG(INFO) << "revokeChallenge";
     if (cb_) {
-        cb_->onStateChanged(0, SessionState::REVOKING_CHALLENGE);
         cb_->onChallengeRevoked(challenge);
-        cb_->onStateChanged(0, SessionState::IDLING);
     }
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::enroll(
-        int32_t /*cookie*/, const keymaster::HardwareAuthToken& /*hat*/,
-        EnrollmentType /*enrollmentType*/, const std::vector<Feature>& /*features*/,
-        const NativeHandle& /*previewSurface*/,
+        const keymaster::HardwareAuthToken& /*hat*/, EnrollmentType /*enrollmentType*/,
+        const std::vector<Feature>& /*features*/, const NativeHandle& /*previewSurface*/,
         std::shared_ptr<biometrics::common::ICancellationSignal>* /*return_val*/) {
     LOG(INFO) << "enroll";
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::authenticate(int32_t /*cookie*/, int64_t /*keystoreOperationId*/,
+ndk::ScopedAStatus Session::authenticate(int64_t /*keystoreOperationId*/,
                                          std::shared_ptr<common::ICancellationSignal>* return_val) {
     LOG(INFO) << "authenticate";
     if (cb_) {
-        cb_->onStateChanged(0, SessionState::AUTHENTICATING);
+        cb_->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
     }
     *return_val = SharedRefBase::make<CancellationSignal>(cb_);
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus Session::detectInteraction(
-        int32_t /*cookie*/, std::shared_ptr<common::ICancellationSignal>* /*return_val*/) {
+        std::shared_ptr<common::ICancellationSignal>* /*return_val*/) {
     LOG(INFO) << "detectInteraction";
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::enumerateEnrollments(int32_t /*cookie*/) {
+ndk::ScopedAStatus Session::enumerateEnrollments() {
     LOG(INFO) << "enumerateEnrollments";
     if (cb_) {
-        cb_->onStateChanged(0, SessionState::ENUMERATING_ENROLLMENTS);
         cb_->onEnrollmentsEnumerated(std::vector<int32_t>());
-        cb_->onStateChanged(0, SessionState::IDLING);
     }
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::removeEnrollments(int32_t /*cookie*/,
-                                              const std::vector<int32_t>& /*enrollmentIds*/) {
+ndk::ScopedAStatus Session::removeEnrollments(const std::vector<int32_t>& /*enrollmentIds*/) {
     LOG(INFO) << "removeEnrollments";
     if (cb_) {
-        cb_->onStateChanged(0, SessionState::REMOVING_ENROLLMENTS);
         cb_->onEnrollmentsRemoved(std::vector<int32_t>());
-        cb_->onStateChanged(0, SessionState::IDLING);
     }
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::getFeatures(int32_t /*cookie*/, int32_t /*enrollmentId*/) {
+ndk::ScopedAStatus Session::getFeatures() {
     LOG(INFO) << "getFeatures";
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::setFeature(int32_t /*cookie*/,
-                                       const keymaster::HardwareAuthToken& /*hat*/,
-                                       int32_t /*enrollmentId*/, Feature /*feature*/,
-                                       bool /*enabled*/) {
+ndk::ScopedAStatus Session::setFeature(const keymaster::HardwareAuthToken& /*hat*/,
+                                       Feature /*feature*/, bool /*enabled*/) {
     LOG(INFO) << "setFeature";
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::getAuthenticatorId(int32_t /*cookie*/) {
+ndk::ScopedAStatus Session::getAuthenticatorId() {
     LOG(INFO) << "getAuthenticatorId";
     if (cb_) {
-        cb_->onStateChanged(0, SessionState::GETTING_AUTHENTICATOR_ID);
         cb_->onAuthenticatorIdRetrieved(0 /* authenticatorId */);
-        cb_->onStateChanged(0, SessionState::IDLING);
     }
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::invalidateAuthenticatorId(int32_t /*cookie*/) {
+ndk::ScopedAStatus Session::invalidateAuthenticatorId() {
     LOG(INFO) << "invalidateAuthenticatorId";
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::resetLockout(int32_t /*cookie*/,
-                                         const keymaster::HardwareAuthToken& /*hat*/) {
+ndk::ScopedAStatus Session::resetLockout(const keymaster::HardwareAuthToken& /*hat*/) {
     LOG(INFO) << "resetLockout";
     if (cb_) {
-        cb_->onStateChanged(0, SessionState::RESETTING_LOCKOUT);
         cb_->onLockoutCleared();
-        cb_->onStateChanged(0, SessionState::IDLING);
     }
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::close(int32_t /*cookie*/) {
+ndk::ScopedAStatus Session::close() {
+    if (cb_) {
+        cb_->onSessionClosed();
+    }
     return ndk::ScopedAStatus::ok();
 }
 
diff --git a/biometrics/face/aidl/default/Session.h b/biometrics/face/aidl/default/Session.h
index eb9ae83..c89985e 100644
--- a/biometrics/face/aidl/default/Session.h
+++ b/biometrics/face/aidl/default/Session.h
@@ -30,40 +30,38 @@
   public:
     explicit Session(std::shared_ptr<ISessionCallback> cb);
 
-    ndk::ScopedAStatus generateChallenge(int32_t cookie) override;
+    ndk::ScopedAStatus generateChallenge() override;
 
-    ndk::ScopedAStatus revokeChallenge(int32_t cookie, int64_t challenge) override;
+    ndk::ScopedAStatus revokeChallenge(int64_t challenge) override;
 
-    ndk::ScopedAStatus enroll(int32_t cookie, const keymaster::HardwareAuthToken& hat,
+    ndk::ScopedAStatus enroll(const keymaster::HardwareAuthToken& hat,
                               EnrollmentType enrollmentType, const std::vector<Feature>& features,
                               const NativeHandle& previewSurface,
                               std::shared_ptr<common::ICancellationSignal>* return_val) override;
 
     ndk::ScopedAStatus authenticate(
-            int32_t cookie, int64_t keystoreOperationId,
+            int64_t keystoreOperationId,
             std::shared_ptr<common::ICancellationSignal>* returnVal) override;
 
     ndk::ScopedAStatus detectInteraction(
-            int32_t cookie, std::shared_ptr<common::ICancellationSignal>* returnVal) override;
+            std::shared_ptr<common::ICancellationSignal>* returnVal) override;
 
-    ndk::ScopedAStatus enumerateEnrollments(int32_t cookie) override;
+    ndk::ScopedAStatus enumerateEnrollments() override;
 
-    ndk::ScopedAStatus removeEnrollments(int32_t cookie,
-                                         const std::vector<int32_t>& enrollmentIds) override;
+    ndk::ScopedAStatus removeEnrollments(const std::vector<int32_t>& enrollmentIds) override;
 
-    ndk::ScopedAStatus getFeatures(int32_t cookie, int32_t enrollmentId) override;
+    ndk::ScopedAStatus getFeatures() override;
 
-    ndk::ScopedAStatus setFeature(int32_t cookie, const keymaster::HardwareAuthToken& hat,
-                                  int32_t enrollmentId, Feature feature, bool enabled) override;
+    ndk::ScopedAStatus setFeature(const keymaster::HardwareAuthToken& hat, Feature feature,
+                                  bool enabled) override;
 
-    ndk::ScopedAStatus getAuthenticatorId(int32_t cookie) override;
+    ndk::ScopedAStatus getAuthenticatorId() override;
 
-    ndk::ScopedAStatus invalidateAuthenticatorId(int32_t cookie) override;
+    ndk::ScopedAStatus invalidateAuthenticatorId() override;
 
-    ndk::ScopedAStatus resetLockout(int32_t cookie,
-                                    const keymaster::HardwareAuthToken& hat) override;
+    ndk::ScopedAStatus resetLockout(const keymaster::HardwareAuthToken& hat) override;
 
-    ndk::ScopedAStatus close(int32_t cookie) override;
+    ndk::ScopedAStatus close() override;
 
   private:
     std::shared_ptr<ISessionCallback> cb_;
diff --git a/biometrics/face/aidl/vts/VtsHalBiometricsFaceTargetTest.cpp b/biometrics/face/aidl/vts/VtsHalBiometricsFaceTargetTest.cpp
index 936fcc6..ada6f73 100644
--- a/biometrics/face/aidl/vts/VtsHalBiometricsFaceTargetTest.cpp
+++ b/biometrics/face/aidl/vts/VtsHalBiometricsFaceTargetTest.cpp
@@ -21,35 +21,31 @@
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 
+#include <chrono>
 #include <future>
 
 namespace aidl::android::hardware::biometrics::face {
 namespace {
 
+using namespace std::literals::chrono_literals;
+
 constexpr int kSensorId = 0;
 constexpr int kUserId = 0;
-constexpr auto kCallbackTimeout = std::chrono::seconds(1);
 
-enum class SessionCallbackMethodName {
-    kOnStateChanged,
+enum class MethodName {
+    kOnError,
+    kOnSessionClosed,
 };
 
-struct SessionCallbackInvocation {
-    SessionCallbackMethodName method_name;
-    SessionState state;
+struct Invocation {
+    MethodName methodName;
+    Error error;
+    int32_t vendorCode;
 };
 
 class SessionCallback : public BnSessionCallback {
   public:
-    explicit SessionCallback(std::promise<SessionCallbackInvocation> invocation_promise)
-        : invocation_promise_(std::move(invocation_promise)) {}
-    ndk::ScopedAStatus onStateChanged(int32_t /*cookie*/, SessionState state) override {
-        SessionCallbackInvocation invocation = {};
-        invocation.method_name = SessionCallbackMethodName::kOnStateChanged;
-        invocation.state = state;
-        invocation_promise_.set_value(invocation);
-        return ndk::ScopedAStatus::ok();
-    }
+    explicit SessionCallback(Invocation* inv) : mInv(inv) {}
 
     ndk::ScopedAStatus onChallengeGenerated(int64_t /*challenge*/) override {
         return ndk::ScopedAStatus::ok();
@@ -67,7 +63,12 @@
         return ndk::ScopedAStatus::ok();
     }
 
-    ndk::ScopedAStatus onError(Error /*error*/, int32_t /*vendorCode*/) override {
+    ndk::ScopedAStatus onError(Error error, int32_t vendorCode) override {
+        *mInv = {};
+        mInv->methodName = MethodName::kOnError;
+        mInv->error = error;
+        mInv->vendorCode = vendorCode;
+
         return ndk::ScopedAStatus::ok();
     }
 
@@ -103,12 +104,11 @@
         return ndk::ScopedAStatus::ok();
     }
 
-    ndk::ScopedAStatus onFeaturesRetrieved(const std::vector<Feature>& /*features*/,
-                                           int32_t /*enrollmentId*/) override {
+    ndk::ScopedAStatus onFeaturesRetrieved(const std::vector<Feature>& /*features*/) override {
         return ndk::ScopedAStatus::ok();
     }
 
-    ndk::ScopedAStatus onFeatureSet(int32_t /*enrollmentId*/, Feature /*feature*/) override {
+    ndk::ScopedAStatus onFeatureSet(Feature /*feature*/) override {
         return ndk::ScopedAStatus::ok();
     }
 
@@ -120,10 +120,15 @@
         return ndk::ScopedAStatus::ok();
     }
 
-    ndk::ScopedAStatus onSessionClosed() override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus onSessionClosed() override {
+        *mInv = {};
+        mInv->methodName = MethodName::kOnSessionClosed;
+
+        return ndk::ScopedAStatus::ok();
+    }
 
   private:
-    std::promise<SessionCallbackInvocation> invocation_promise_;
+    Invocation* mInv;
 };
 
 class Face : public testing::TestWithParam<std::string> {
@@ -131,28 +136,34 @@
     void SetUp() override {
         AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
         ASSERT_NE(binder, nullptr);
-        hal_ = IFace::fromBinder(ndk::SpAIBinder(binder));
+        mHal = IFace::fromBinder(ndk::SpAIBinder(binder));
     }
 
-    std::shared_ptr<IFace> hal_;
+    std::shared_ptr<IFace> mHal;
+    Invocation mInv;
 };
 
 TEST_P(Face, AuthenticateTest) {
-    std::promise<SessionCallbackInvocation> invocation_promise;
-    std::future<SessionCallbackInvocation> invocation_future = invocation_promise.get_future();
-    std::shared_ptr<SessionCallback> session_cb =
-            ndk::SharedRefBase::make<SessionCallback>(std::move(invocation_promise));
+    // Prepare the callback.
+    auto cb = ndk::SharedRefBase::make<SessionCallback>(&mInv);
 
+    // Create a session
     std::shared_ptr<ISession> session;
-    ASSERT_TRUE(hal_->createSession(kSensorId, kUserId, session_cb, &session).isOk());
+    ASSERT_TRUE(mHal->createSession(kSensorId, kUserId, cb, &session).isOk());
 
-    std::shared_ptr<common::ICancellationSignal> cancel_cb;
-    ASSERT_TRUE(session->authenticate(0, 0, &cancel_cb).isOk());
-    ASSERT_EQ(invocation_future.wait_for(kCallbackTimeout), std::future_status::ready);
+    // Call authenticate
+    std::shared_ptr<common::ICancellationSignal> cancellationSignal;
+    ASSERT_TRUE(session->authenticate(0 /* operationId */, &cancellationSignal).isOk());
 
-    SessionCallbackInvocation invocation = invocation_future.get();
-    EXPECT_EQ(invocation.method_name, SessionCallbackMethodName::kOnStateChanged);
-    EXPECT_EQ(invocation.state, SessionState::AUTHENTICATING);
+    // Get the results
+    EXPECT_EQ(mInv.methodName, MethodName::kOnError);
+    EXPECT_EQ(mInv.error, Error::UNABLE_TO_PROCESS);
+    EXPECT_EQ(mInv.vendorCode, 0);
+
+    // Close the session
+    ASSERT_TRUE(session->close().isOk());
+
+    EXPECT_EQ(mInv.methodName, MethodName::kOnSessionClosed);
 }
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Face);
@@ -161,6 +172,7 @@
                          ::android::PrintInstanceNameToString);
 
 }  // namespace
+}  // namespace aidl::android::hardware::biometrics::face
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
@@ -169,4 +181,3 @@
     return RUN_ALL_TESTS();
 }
 
-}  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
index a8e73fc..2c2011a 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
@@ -45,4 +45,5 @@
   TOO_DARK = 8,
   TOO_BRIGHT = 9,
   IMMOBILE = 10,
+  RETRYING_CAPTURE = 11,
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
index 87eaf96..9934a76 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -34,17 +34,17 @@
 package android.hardware.biometrics.fingerprint;
 @VintfStability
 interface ISession {
-  void generateChallenge(in int cookie);
-  void revokeChallenge(in int cookie, in long challenge);
-  android.hardware.biometrics.common.ICancellationSignal enroll(in int cookie, in android.hardware.keymaster.HardwareAuthToken hat);
-  android.hardware.biometrics.common.ICancellationSignal authenticate(in int cookie, in long operationId);
-  android.hardware.biometrics.common.ICancellationSignal detectInteraction(in int cookie);
-  void enumerateEnrollments(in int cookie);
-  void removeEnrollments(in int cookie, in int[] enrollmentIds);
-  void getAuthenticatorId(in int cookie);
-  void invalidateAuthenticatorId(in int cookie);
-  void resetLockout(in int cookie, in android.hardware.keymaster.HardwareAuthToken hat);
-  void close(in int cookie);
+  void generateChallenge();
+  void revokeChallenge(in long challenge);
+  android.hardware.biometrics.common.ICancellationSignal enroll(in android.hardware.keymaster.HardwareAuthToken hat);
+  android.hardware.biometrics.common.ICancellationSignal authenticate(in long operationId);
+  android.hardware.biometrics.common.ICancellationSignal detectInteraction();
+  void enumerateEnrollments();
+  void removeEnrollments(in int[] enrollmentIds);
+  void getAuthenticatorId();
+  void invalidateAuthenticatorId();
+  void resetLockout(in android.hardware.keymaster.HardwareAuthToken hat);
+  void close();
   void onPointerDown(in int pointerId, in int x, in int y, in float minor, in float major);
   void onPointerUp(in int pointerId);
   void onUiReady();
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
index 3a97717..3c40ad6 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
@@ -34,7 +34,6 @@
 package android.hardware.biometrics.fingerprint;
 @VintfStability
 interface ISessionCallback {
-  void onStateChanged(in int cookie, in android.hardware.biometrics.fingerprint.SessionState state);
   void onChallengeGenerated(in long challenge);
   void onChallengeRevoked(in long challenge);
   void onAcquired(in android.hardware.biometrics.fingerprint.AcquiredInfo info, in int vendorCode);
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
index bf11daa..b406947 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
@@ -82,5 +82,11 @@
      * same finger can help against false rejections.
      */
     IMMOBILE,
-}
 
+    /**
+     * This message may be sent to notify the framework that an additional image capture is taking
+     * place. Multiple RETRYING_CAPTURE may be sent before an ACQUIRED_GOOD message is sent.
+     * However, RETRYING_CAPTURE must not be sent after ACQUIRED_GOOD is sent.
+     */
+    RETRYING_CAPTURE,
+}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
index 98a4530..271a9bf 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
@@ -32,27 +32,14 @@
     /**
      * createSession:
      *
-     * Creates a session which can then be used by the framework to perform operations such as
-     * enroll, authenticate, etc for the given sensorId and userId.
+     * Creates a instance of ISession which can be used by the framework to perform operations
+     * such as ISession#enroll, ISession#authenticate, etc. for the given sensorId and userId.
      *
-     * Calling this method while there is an active session is considered an error. If the
-     * framework is in a bad state and for some reason cannot close its session, it should use
-     * the reset method below.
-     *
-     * A physical sensor identified by sensorId typically supports only a single in-flight session
-     * at a time. As such, if a session is currently in a state other than SessionState::IDLING, the
-     * HAL MUST finish or cancel the current operation and return to SessionState::IDLING before the
-     * new session is created. For example:
-     *   1) If a session for sensorId=0, userId=0 is currently in a cancellable state (see
-     *      ICancellationSignal) such as SessionState::AUTHENTICATING and the framework requests a
-     *      new session for sensorId=0, userId=10, the HAL must end the current session with
-     *      Error::CANCELED, invoke ISessionCallback#onStateChanged with SessionState::IDLING, and
-     *      then return a new session for sensorId=0, userId=10.
-     *   2) If a session for sensorId=0, userId=0 is currently in a non-cancellable state such as
-     *      SessionState::REMOVING_ENROLLMENTS, and the framework requests a new session for
-     *      sensorId=0, userId=10, the HAL must finish the current operation before invoking
-     *      ISessionCallback#onStateChanged with SessionState::IDLING, and return a new session for
-     *      sensorId=0, userId=10.
+     * Calling this method while there is an active session is considered an error. If the framework
+     * wants to create a new session when it already has an active session, it must first cancel the
+     * current operation if it's cancellable, or wait until it completes. Then, the framework must
+     * explicitly close the session with ISession#close. Once the framework receives
+     * ISessionCallback#onSessionClosed, a new session can be created.
      *
      * Implementations must store user-specific state or metadata in /data/vendor_de/<user>/fpdata
      * as specified by the SeLinux policy. This directory is created/removed by vold (see
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
index ef2e6fc..940548b 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -22,23 +22,28 @@
 /**
  * Operations that can be performed for unique sessions retrieved via IFingerprint#createSession.
  * Methods defined within this interface can be split into the following categories:
- *   1) Methods associated with a state (see the SessionState enum). State-based operations are
- *      handled by the HAL in FIFO order.
- *   1a) Cancellable state-based operations. If a cancellable operation is in-progress and the
- *       framework requests a subsequent state-based operation, the implementation should finish
- *       the operation via ISessionCallback#onError with Error::CANCELED.
- *   1b) Non-cancellable state-based operations. These operations should fully complete before the
- *       next state-based operation can be started.
- *   2) Methods without a state. These methods may be invoked by the framework depending on its
- *      use case. For example on devices with sensors of FingerprintSensorType::UNDER_DISPLAY_*,
- *      ISession#onFingerDown may be invoked while the HAL is in SessionState::ENROLLING,
- *      SessionState::AUTHENTICATING, or SessionState::DETECTING_INTERACTION.
+ *   1) Non-interrupting operations. These operations are handled by the HAL in FIFO order.
+ *   1a) Cancellable operations. These are usually the operations that can execute for several
+ *       minutes. To allow for cancellation, they return an instance of ICancellationSignal that
+ *       lets the framework cancel them by calling ICancellationSignal#cancel. If such an operation
+ *       is cancelled, it must notify the framework by calling ISessionCallback#onError with
+ *       Error::CANCELED.
+ *   1b) Non-cancellable operations. Such operations cannot be cancelled once started.
+ *   2) Interrupting operations. These operations may be invoked by the framework immediately,
+ *      regardless of whether another operation is executing. For example, on devices with sensors
+ *      of FingerprintSensorType::UNDER_DISPLAY_*, ISession#onFingerDown may be invoked while the
+ *      HAL is executing ISession#enroll, ISession#authenticate or ISession#detectInteraction.
  *
- * If the HAL has multiple operations in its queue, it is not required to notify the framework
- * of SessionState::IDLING between each operation. However, it must notify the framework when all
- * work is completed. See ISessionCallback#onStateChanged. For example, the following is a valid
- * sequence of ISessionCallback#onStateChanged invocations: SessionState::IDLING -->
- * SessionState::ENROLLING --> SessionState::ENUMERATING_ENROLLMENTS --> SessionState::IDLING.
+ * The lifecycle of a non-interrupting operation ends when one of its terminal callbacks is called.
+ * For example, ISession#authenticate is considered completed when either of the following callbacks
+ * is called: ISessionCallback#onError or ISessionCallback#onAuthenticationSucceeded.
+ *
+ * The lifecycle of an interrupting operation ends when it returns. Interrupting operations do not
+ * have callbacks.
+ *
+ * ISession only supports execution of one non-interrupting operation at a time, regardless of
+ * whether it's cancellable. The framework must wait for a corresponding callback indicating the end of
+ * the current non-interrupting operation before a new non-interrupting operation can be started.
  */
 @VintfStability
 interface ISession {
@@ -84,9 +89,8 @@
      * | 0        | 10     | <Time4>    | <Random4> |
      * ----------------------------------------------
      *
-     * @param cookie A unique number identifying this operation
      */
-    void generateChallenge(in int cookie);
+    void generateChallenge();
 
     /**
      * revokeChallenge:
@@ -95,23 +99,17 @@
      * parameters is requested, the implementation must still notify the framework using the
      * provided callback.
      *
-     * @param cookie A unique number identifying this operation
      * @param challenge Challenge that should be revoked.
      */
-    void revokeChallenge(in int cookie, in long challenge);
+    void revokeChallenge(in long challenge);
 
     /**
      * enroll:
      *
      * A request to add a fingerprint enrollment.
      *
-     * Once the HAL is able to start processing the enrollment request, it must notify the framework
-     * via ISessionCallback#onStateChanged with SessionState::ENROLLING.
-     *
      * At any point during enrollment, if a non-recoverable error occurs, the HAL must notify the
-     * framework via ISessionCallback#onError with the applicable enrollment-specific error, and
-     * then send ISessionCallback#onStateChanged(cookie, SessionState::IDLING) if no subsequent
-     * operation is in the queue.
+     * framework via ISessionCallback#onError with the applicable enrollment-specific error.
      *
      * Before capturing fingerprint data, the implementation must first verify the authenticity and
      * integrity of the provided HardwareAuthToken. In addition, it must check that the challenge
@@ -132,24 +130,17 @@
      * implementation MUST update and associate this (sensorId, userId) pair with a new new
      * entropy-encoded random identifier. See ISession#getAuthenticatorId for more information.
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path. The
-     *               client must guarantee that it is unique per ISession.
      * @param hat See above documentation.
      */
-    ICancellationSignal enroll(in int cookie, in HardwareAuthToken hat);
+    ICancellationSignal enroll(in HardwareAuthToken hat);
 
     /**
      * authenticate:
      *
      * A request to start looking for fingerprints to authenticate.
      *
-     * Once the HAL is able to start processing the authentication request, it must notify framework
-     * via ISessionCallback#onStateChanged with SessionState::AUTHENTICATING.
-     *
      * At any point during authentication, if a non-recoverable error occurs, the HAL must notify
-     * the framework via ISessionCallback#onError with the applicable authentication-specific error,
-     * and then send ISessionCallback#onStateChanged(cookie, SessionState::IDLING) if no
-     * subsequent operation is in the queue.
+     * the framework via ISessionCallback#onError with the applicable authentication-specific error.
      *
      * During authentication, the implementation may notify the framework via
      * ISessionCallback#onAcquired with messages that may be used to guide the user. This callback
@@ -171,8 +162,6 @@
      * must be set with the operationId passed in during #authenticate. If the sensor is NOT
      * SensorStrength::STRONG, the HardwareAuthToken MUST be null.
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path. The
-     *               client must guarantee that it is unique per ISession.
      * @param operationId For sensors configured as SensorStrength::STRONG, this must be used ONLY
      *                    upon successful authentication and wrapped in the HardwareAuthToken's
      *                    "challenge" field and sent to the framework via
@@ -184,7 +173,7 @@
      *                    setUserAuthenticationParameters in KeyGenParameterSpec.Builder and
      *                    KeyProtection.Builder.
      */
-    ICancellationSignal authenticate(in int cookie, in long operationId);
+    ICancellationSignal authenticate(in long operationId);
 
     /**
      * detectInteraction:
@@ -193,17 +182,12 @@
      * if SensorProps#supportsDetectInteraction is true. If invoked on implementations that do not
      * support this functionality, the HAL must respond with ISession#onError(UNABLE_TO_PROCESS, 0).
      *
-     * Once the HAL is able to start processing this request, it must notify the framework via
-     * ISessionCallback#onStateChanged with SessionState::DETECTING_INTERACTION.
-     *
      * The framework will use this method in cases where determing user presence is required, but
      * identifying/authentication is not. For example, when the device is encrypted (first boot) or
      * in lockdown mode.
      *
      * At any point during detectInteraction, if a non-recoverable error occurs, the HAL must notify
-     * the framework via ISessionCallback#onError with the applicable error, and then send
-     * ISessionCallback#onStateChanged(cookie, SessionState::IDLING) if no subsequent operation is
-     * in the queue.
+     * the framework via ISessionCallback#onError with the applicable error.
      *
      * The implementation must only check for a fingerprint-like image was detected (e.g. to
      * minimize interactions due to non-fingerprint objects), and the lockout counter must not
@@ -221,10 +205,8 @@
      * Note that if the operation is canceled, the implementation must notify the framework via
      * ISessionCallback#onError with Error::CANCELED.
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path.
-     *               The framework will guarantee that it is unique per ISession.
      */
-    ICancellationSignal detectInteraction(in int cookie);
+    ICancellationSignal detectInteraction();
 
     /*
      * enumerateEnrollments:
@@ -232,32 +214,22 @@
      * A request to enumerate (list) the enrollments for this (sensorId, userId) pair. The
      * framework typically uses this to ensure that its cache is in sync with the HAL.
      *
-     * Once the HAL is able to start processing this request, it must notify the framework via
-     * ISessionCallback#onStateChanged with SessionState::ENUMERATING_ENROLLMENTS.
-     *
      * The implementation must then notify the framework with a list of enrollments applicable
      * for the current session via ISessionCallback#onEnrollmentsEnumerated.
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path.
-     *               The framework will guarantee that it is unique per ISession.
      */
-    void enumerateEnrollments(in int cookie);
+    void enumerateEnrollments();
 
     /**
      * removeEnrollments:
      *
      * A request to remove the enrollments for this (sensorId, userId) pair.
      *
-     * Once the HAL is able to start processing this request, it must notify the framework via
-     * ISessionCallback#onStateChanged with SessionState::REMOVING_ENROLLMENTS.
-     *
      * After removing the enrollmentIds from everywhere necessary (filesystem, secure subsystems,
      * etc), the implementation must notify the framework via ISessionCallback#onEnrollmentsRemoved.
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path.
-     *               The framework will guarantee that it is unique per ISession.
      */
-    void removeEnrollments(in int cookie, in int[] enrollmentIds);
+    void removeEnrollments(in int[] enrollmentIds);
 
     /**
      * getAuthenticatorId:
@@ -285,10 +257,8 @@
      *   3) MUST not change if a fingerprint is deleted.
      *   4) MUST be an entropy-encoded random number
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path. The
-     *               client must guarantee that it is unique per ISession.
      */
-    void getAuthenticatorId(in int cookie);
+    void getAuthenticatorId();
 
     /**
      * invalidateAuthenticatorId:
@@ -312,10 +282,8 @@
      * for more details). As such, the framework would coordinate invalidation across multiple
      * biometric HALs as necessary.
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path. The
-     *               client must guarantee that it is unique per ISession.
      */
-    void invalidateAuthenticatorId(in int cookie);
+    void invalidateAuthenticatorId();
 
     /**
      * resetLockout:
@@ -326,8 +294,7 @@
      *   2) Verify that the timestamp provided within the HAT is relatively recent (e.g. on the
      *      order of minutes, not hours).
      * If either of the checks fail, the HAL must invoke ISessionCallback#onError with
-     * Error::UNABLE_TO_PROCESS and return to SessionState::IDLING if no subsequent work is in the
-     * queue.
+     * Error::UNABLE_TO_PROCESS and return to the idling state.
      *
      * Upon successful verification, the HAL must clear the lockout counter and notify the framework
      * via ISessionCallback#onLockoutCleared.
@@ -358,29 +325,26 @@
      * See the Android CDD section 7.3.10 for the full set of lockout and rate-limiting
      * requirements.
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path. The
-     *               client must guarantee that it is unique per ISession.
      * @param hat HardwareAuthToken See above documentation.
      */
-    void resetLockout(in int cookie, in HardwareAuthToken hat);
+    void resetLockout(in HardwareAuthToken hat);
 
     /*
      * Close this session and allow the HAL to release the resources associated with this session.
      *
-     * A session can only be closed when it's in SessionState::IDLING. Closing a session will
-     * result in a ISessionCallback#onStateChanged call with SessionState::CLOSED.
+     * A session can only be closed when the HAL is idling, i.e. not performing any of the
+     * non-interruptable operations. If the HAL is busy performing a cancellable operation, the
+     * operation must be explicitly cancelled with a call to ICancellationSignal#cancel before
+     * the session can be closed.
      *
-     * If a session is unresponsive or stuck in a state other than SessionState::CLOSED,
-     * IFingerprint#reset could be used as a last resort to terminate the session and recover the
-     * HAL from a bad state.
+     * After a session is closed, the HAL must notify the framework by calling
+     * ISessionCallback#onSessionClosed.
      *
      * All sessions must be explicitly closed. Calling IFingerprint#createSession while there is an
      * active session is considered an error.
      *
-     * @param cookie An identifier used to track subsystem operations related to this call path. The
-     *               client must guarantee that it is unique per ISession.
      */
-    void close(in int cookie);
+    void close();
 
     /**
      * Methods for notifying the under-display fingerprint sensor about external events.
@@ -394,9 +358,8 @@
      * of other types, the HAL must treat this as a no-op and return immediately.
      *
      * For sensors of type FingerprintSensorType::UNDER_DISPLAY_*, this method is used to notify the
-     * HAL of display touches. This method can be invoked when the session is in one of the
-     * following states: SessionState::ENROLLING, SessionState::AUTHENTICATING, or
-     * SessionState::DETECTING_INTERACTION.
+     * HAL of display touches. This method can be invoked when the HAL is performing any one of:
+     * ISession#authenticate, ISession#enroll, ISession#detectInteraction.
      *
      * Note that the framework will only invoke this method if the event occurred on the display on
      * which this sensor is located.
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
index cf3a271..95657b3 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
@@ -18,17 +18,11 @@
 
 import android.hardware.biometrics.fingerprint.AcquiredInfo;
 import android.hardware.biometrics.fingerprint.Error;
-import android.hardware.biometrics.fingerprint.SessionState;
 import android.hardware.keymaster.HardwareAuthToken;
 
 @VintfStability
 interface ISessionCallback {
     /**
-     * Used to notify the framework of session state changes. See ISession for more information.
-     */
-    void onStateChanged(in int cookie, in SessionState state);
-
-    /**
      * Notifies the framework when a challenge is successfully generated.
      */
     void onChallengeGenerated(in long challenge);
@@ -39,10 +33,10 @@
     void onChallengeRevoked(in long challenge);
 
     /**
-     * This method must only be used to notify the framework during the following states:
-     *   1) SessionState::ENROLLING
-     *   2) SessionState::AUTHENTICATING
-     *   3) SessionState::DETECTING_INTERACTION
+     * This method must only be used to notify the framework during the following operations:
+     *   1) ISession#enroll
+     *   2) ISession#authenticate
+     *   3) ISession#detectInteraction
      *
      * These messages may be used to provide user guidance multiple times if necessary per
      * operation.
@@ -56,18 +50,18 @@
     void onAcquired(in AcquiredInfo info, in int vendorCode);
 
     /**
-     * This method must only be used to notify the framework during the following states:
-     *   1) SessionState::ENROLLING
-     *   2) SessionState::AUTHENTICATING
-     *   3) SessionState::DETECTING_INTERACTION
-     *   4) SessionState::INVALIDATING_AUTHENTICATOR_ID
-     *   5) SessionState::RESETTING_LOCKOUT
+     * This method must only be used to notify the framework during the following operations:
+     *   1) ISession#enroll
+     *   2) ISession#authenticate
+     *   3) ISession#detectInteraction
+     *   4) ISession#invalidateAuthenticatorId
+     *   5) ISession#resetLockout
      *
      * These messages may be used to notify the framework or user that a non-recoverable error
-     * has occurred. The operation is finished, and the HAL must proceed with the next operation
-     * or return to SessionState::IDLING if the queue is empty.
+     * has occurred. The operation is finished, and the HAL can proceed with the next operation
+     * or return to the idling state.
      *
-     * Note that cancellation (see common::ICancellationSignal) and preemption most be followed with
+     * Note that cancellation (see common::ICancellationSignal) and preemption must be followed with
      * an Error::CANCELED message.
      *
      * @param error See the Error enum.
@@ -79,8 +73,7 @@
     void onError(in Error error, in int vendorCode);
 
     /**
-     * This method must only be used to notify the framework during the following state:
-     *   1) SessionState::ENROLLING
+     * This method must only be used to notify the framework during the ISession#enroll operation.
      *
      * @param enrollmentId Unique stable identifier for the enrollment that's being added by this
      *                     ISession#enroll invocation.
@@ -89,7 +82,7 @@
     void onEnrollmentProgress(in int enrollmentId, int remaining);
 
     /**
-     * This method must only be used to notify the framework during SessionState::AUTHENTICATING.
+     * This method must only be used to notify the framework during ISession#authenticate.
      *
      * Used to notify the framework upon successful authentication. Note that the authentication
      * lifecycle ends when either 1) a fingerprint is accepted, or 2) an error occurred. The
@@ -104,7 +97,7 @@
     void onAuthenticationSucceeded(in int enrollmentId, in HardwareAuthToken hat);
 
     /**
-     * This method must only be used to notify the framework during SessionState::AUTHENTICATING.
+     * This method must only be used to notify the framework during ISession#authenticate.
      *
      * Used to notify the framework upon rejected attempts. Note that the authentication
      * lifecycle ends when either 1) a fingerprint is accepted, or 2) an occurred. The
@@ -113,7 +106,7 @@
     void onAuthenticationFailed();
 
     /**
-     * This method must only be used to notify the framework during SessionState::AUTHENTICATING.
+     * This method must only be used to notify the framework during ISession#authenticate.
      *
      * Authentication is locked out due to too many unsuccessful attempts. This is a rate-limiting
      * lockout, and authentication can be restarted after a period of time. See
@@ -126,7 +119,7 @@
     void onLockoutTimed(in long durationMillis);
 
     /**
-     * This method must only be used to notify the framework during SessionState::AUTHENTICATING.
+     * This method must only be used to notify the framework during ISession#authenticate.
      *
      * Authentication is disabled until the user unlocks with their device credential
      * (PIN/Pattern/Password). See ISession#resetLockout.
@@ -153,7 +146,7 @@
 
     /**
      * This method must only be used to notify the framework during
-     * SessionState::DETECTING_INTERACTION
+     * ISession#detectInteraction
      *
      * Notifies the framework that user interaction occurred. See ISession#detectInteraction.
      */
@@ -161,7 +154,7 @@
 
     /**
      * This method must only be used to notify the framework during
-     * SessionState::ENUMERATING_ENROLLMENTS.
+     * ISession#enumerateEnrollments.
      *
      * Notifies the framework of the current enrollments. See ISession#enumerateEnrollments.
      *
@@ -171,7 +164,7 @@
 
     /**
      * This method must only be used to notify the framework during
-     * SessionState::REMOVING_ENROLLMENTS.
+     * ISession#removeEnrollments.
      *
      * Notifies the framework that the specified enrollments are removed.
      *
@@ -181,7 +174,7 @@
 
     /**
      * This method must only be used to notify the framework during
-     * SessionState::GETTING_AUTHENTICATOR_ID.
+     * ISession#getAuthenticatorId.
      *
      * Notifies the framework with the authenticatorId corresponding to this session's
      * (userId, sensorId) pair.
@@ -192,7 +185,7 @@
 
     /**
      * This method must only be used to notify the framework during
-     * SessionState::INVALIDATING_AUTHENTICATOR_ID.
+     * ISession#invalidateAuthenticatorId.
      *
      * See ISession#invalidateAuthenticatorId for more information.
      *
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SessionState.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SessionState.aidl
deleted file mode 100644
index 19a6ce3..0000000
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SessionState.aidl
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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.
- */
-
-package android.hardware.biometrics.fingerprint;
-
-@VintfStability
-@Backing(type="byte")
-enum SessionState {
-    /**
-     * The HAL is not processing any session requests.
-     */
-    IDLING,
-
-    /**
-     * The session has been closed by the client.
-     */
-    CLOSED,
-
-    /**
-     * The HAL is processing the ISession#generateChallenge request.
-     */
-    GENERATING_CHALLENGE,
-
-    /**
-     * The HAL is processing the ISession#revokeChallenge request.
-     */
-    REVOKING_CHALLENGE,
-
-    /**
-     * The HAL is processing the ISession#enroll request.
-     */
-    ENROLLING,
-
-    /**
-     * The HAL is processing the ISession#authenticate request.
-     */
-    AUTHENTICATING,
-
-    /**
-     * The HAL is processing the ISession#detectInteraction request.
-     */
-    DETECTING_INTERACTION,
-
-    /**
-     * The HAL is processing the ISession#enumerateEnrollments request.
-     */
-    ENUMERATING_ENROLLMENTS,
-
-    /**
-     * The HAL is processing the ISession#removeEnrollments request.
-     */
-    REMOVING_ENROLLMENTS,
-
-    /**
-     * The HAL is processing the ISession#getAuthenticatorId request.
-     */
-    GETTING_AUTHENTICATOR_ID,
-
-    /**
-     * The HAL is processing the ISession#invalidateAuthenticatorId request.
-     */
-    INVALIDATING_AUTHENTICATOR_ID,
-
-    /**
-     * The HAL is processing the ISession#resetLockout request.
-     */
-    RESETTING_LOCKOUT
-}
diff --git a/biometrics/fingerprint/aidl/default/Session.cpp b/biometrics/fingerprint/aidl/default/Session.cpp
index f030f13..ca481e7 100644
--- a/biometrics/fingerprint/aidl/default/Session.cpp
+++ b/biometrics/fingerprint/aidl/default/Session.cpp
@@ -39,54 +39,56 @@
 }
 
 void Session::scheduleStateOrCrash(SessionState state) {
-    CHECK(mScheduledState == SessionState::IDLING);
-    CHECK(mCurrentState == SessionState::IDLING);
+    // TODO(b/166800618): call enterIdling from the terminal callbacks and restore these checks.
+    // CHECK(mScheduledState == SessionState::IDLING);
+    // CHECK(mCurrentState == SessionState::IDLING);
     mScheduledState = state;
 }
 
-void Session::enterStateOrCrash(int cookie, SessionState state) {
+void Session::enterStateOrCrash(SessionState state) {
     CHECK(mScheduledState == state);
     mCurrentState = state;
     mScheduledState = SessionState::IDLING;
-    mCb->onStateChanged(cookie, mCurrentState);
 }
 
-void Session::enterIdling(int cookie) {
-    mCurrentState = SessionState::IDLING;
-    mCb->onStateChanged(cookie, mCurrentState);
+void Session::enterIdling() {
+    // TODO(b/166800618): call enterIdling from the terminal callbacks and rethink this conditional.
+    if (mCurrentState != SessionState::CLOSED) {
+        mCurrentState = SessionState::IDLING;
+    }
 }
 
 bool Session::isClosed() {
     return mCurrentState == SessionState::CLOSED;
 }
 
-ndk::ScopedAStatus Session::generateChallenge(int32_t cookie) {
+ndk::ScopedAStatus Session::generateChallenge() {
     LOG(INFO) << "generateChallenge";
     scheduleStateOrCrash(SessionState::GENERATING_CHALLENGE);
 
-    mWorker->schedule(Callable::from([this, cookie] {
-        enterStateOrCrash(cookie, SessionState::GENERATING_CHALLENGE);
+    mWorker->schedule(Callable::from([this] {
+        enterStateOrCrash(SessionState::GENERATING_CHALLENGE);
         mEngine->generateChallengeImpl(mCb.get());
-        enterIdling(cookie);
+        enterIdling();
     }));
 
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::revokeChallenge(int32_t cookie, int64_t challenge) {
+ndk::ScopedAStatus Session::revokeChallenge(int64_t challenge) {
     LOG(INFO) << "revokeChallenge";
     scheduleStateOrCrash(SessionState::REVOKING_CHALLENGE);
 
-    mWorker->schedule(Callable::from([this, cookie, challenge] {
-        enterStateOrCrash(cookie, SessionState::REVOKING_CHALLENGE);
+    mWorker->schedule(Callable::from([this, challenge] {
+        enterStateOrCrash(SessionState::REVOKING_CHALLENGE);
         mEngine->revokeChallengeImpl(mCb.get(), challenge);
-        enterIdling(cookie);
+        enterIdling();
     }));
 
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::enroll(int32_t cookie, const keymaster::HardwareAuthToken& hat,
+ndk::ScopedAStatus Session::enroll(const keymaster::HardwareAuthToken& hat,
                                    std::shared_ptr<common::ICancellationSignal>* out) {
     LOG(INFO) << "enroll";
     scheduleStateOrCrash(SessionState::ENROLLING);
@@ -94,21 +96,21 @@
     std::promise<void> cancellationPromise;
     auto cancFuture = cancellationPromise.get_future();
 
-    mWorker->schedule(Callable::from([this, cookie, hat, cancFuture = std::move(cancFuture)] {
-        enterStateOrCrash(cookie, SessionState::ENROLLING);
+    mWorker->schedule(Callable::from([this, hat, cancFuture = std::move(cancFuture)] {
+        enterStateOrCrash(SessionState::ENROLLING);
         if (shouldCancel(cancFuture)) {
             mCb->onError(Error::CANCELED, 0 /* vendorCode */);
         } else {
             mEngine->enrollImpl(mCb.get(), hat);
         }
-        enterIdling(cookie);
+        enterIdling();
     }));
 
     *out = SharedRefBase::make<CancellationSignal>(std::move(cancellationPromise));
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::authenticate(int32_t cookie, int64_t operationId,
+ndk::ScopedAStatus Session::authenticate(int64_t operationId,
                                          std::shared_ptr<common::ICancellationSignal>* out) {
     LOG(INFO) << "authenticate";
     scheduleStateOrCrash(SessionState::AUTHENTICATING);
@@ -116,112 +118,111 @@
     std::promise<void> cancPromise;
     auto cancFuture = cancPromise.get_future();
 
-    mWorker->schedule(
-            Callable::from([this, cookie, operationId, cancFuture = std::move(cancFuture)] {
-                enterStateOrCrash(cookie, SessionState::AUTHENTICATING);
-                if (shouldCancel(cancFuture)) {
-                    mCb->onError(Error::CANCELED, 0 /* vendorCode */);
-                } else {
-                    mEngine->authenticateImpl(mCb.get(), operationId);
-                }
-                enterIdling(cookie);
-            }));
+    mWorker->schedule(Callable::from([this, operationId, cancFuture = std::move(cancFuture)] {
+        enterStateOrCrash(SessionState::AUTHENTICATING);
+        if (shouldCancel(cancFuture)) {
+            mCb->onError(Error::CANCELED, 0 /* vendorCode */);
+        } else {
+            mEngine->authenticateImpl(mCb.get(), operationId);
+        }
+        enterIdling();
+    }));
 
     *out = SharedRefBase::make<CancellationSignal>(std::move(cancPromise));
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::detectInteraction(int32_t cookie,
-                                              std::shared_ptr<common::ICancellationSignal>* out) {
+ndk::ScopedAStatus Session::detectInteraction(std::shared_ptr<common::ICancellationSignal>* out) {
     LOG(INFO) << "detectInteraction";
     scheduleStateOrCrash(SessionState::DETECTING_INTERACTION);
 
     std::promise<void> cancellationPromise;
     auto cancFuture = cancellationPromise.get_future();
 
-    mWorker->schedule(Callable::from([this, cookie, cancFuture = std::move(cancFuture)] {
-        enterStateOrCrash(cookie, SessionState::DETECTING_INTERACTION);
+    mWorker->schedule(Callable::from([this, cancFuture = std::move(cancFuture)] {
+        enterStateOrCrash(SessionState::DETECTING_INTERACTION);
         if (shouldCancel(cancFuture)) {
             mCb->onError(Error::CANCELED, 0 /* vendorCode */);
         } else {
             mEngine->detectInteractionImpl(mCb.get());
         }
-        enterIdling(cookie);
+        enterIdling();
     }));
 
     *out = SharedRefBase::make<CancellationSignal>(std::move(cancellationPromise));
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::enumerateEnrollments(int32_t cookie) {
+ndk::ScopedAStatus Session::enumerateEnrollments() {
     LOG(INFO) << "enumerateEnrollments";
     scheduleStateOrCrash(SessionState::ENUMERATING_ENROLLMENTS);
 
-    mWorker->schedule(Callable::from([this, cookie] {
-        enterStateOrCrash(cookie, SessionState::ENUMERATING_ENROLLMENTS);
+    mWorker->schedule(Callable::from([this] {
+        enterStateOrCrash(SessionState::ENUMERATING_ENROLLMENTS);
         mEngine->enumerateEnrollmentsImpl(mCb.get());
-        enterIdling(cookie);
+        enterIdling();
     }));
 
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::removeEnrollments(int32_t cookie,
-                                              const std::vector<int32_t>& enrollmentIds) {
+ndk::ScopedAStatus Session::removeEnrollments(const std::vector<int32_t>& enrollmentIds) {
     LOG(INFO) << "removeEnrollments";
     scheduleStateOrCrash(SessionState::REMOVING_ENROLLMENTS);
 
-    mWorker->schedule(Callable::from([this, cookie, enrollmentIds] {
-        enterStateOrCrash(cookie, SessionState::REMOVING_ENROLLMENTS);
+    mWorker->schedule(Callable::from([this, enrollmentIds] {
+        enterStateOrCrash(SessionState::REMOVING_ENROLLMENTS);
         mEngine->removeEnrollmentsImpl(mCb.get(), enrollmentIds);
-        enterIdling(cookie);
+        enterIdling();
     }));
 
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::getAuthenticatorId(int32_t cookie) {
+ndk::ScopedAStatus Session::getAuthenticatorId() {
     LOG(INFO) << "getAuthenticatorId";
     scheduleStateOrCrash(SessionState::GETTING_AUTHENTICATOR_ID);
 
-    mWorker->schedule(Callable::from([this, cookie] {
-        enterStateOrCrash(cookie, SessionState::GETTING_AUTHENTICATOR_ID);
+    mWorker->schedule(Callable::from([this] {
+        enterStateOrCrash(SessionState::GETTING_AUTHENTICATOR_ID);
         mEngine->getAuthenticatorIdImpl(mCb.get());
-        enterIdling(cookie);
+        enterIdling();
     }));
 
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::invalidateAuthenticatorId(int32_t cookie) {
+ndk::ScopedAStatus Session::invalidateAuthenticatorId() {
     LOG(INFO) << "invalidateAuthenticatorId";
     scheduleStateOrCrash(SessionState::INVALIDATING_AUTHENTICATOR_ID);
 
-    mWorker->schedule(Callable::from([this, cookie] {
-        enterStateOrCrash(cookie, SessionState::INVALIDATING_AUTHENTICATOR_ID);
+    mWorker->schedule(Callable::from([this] {
+        enterStateOrCrash(SessionState::INVALIDATING_AUTHENTICATOR_ID);
         mEngine->invalidateAuthenticatorIdImpl(mCb.get());
-        enterIdling(cookie);
+        enterIdling();
     }));
 
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::resetLockout(int32_t cookie, const keymaster::HardwareAuthToken& hat) {
+ndk::ScopedAStatus Session::resetLockout(const keymaster::HardwareAuthToken& hat) {
     LOG(INFO) << "resetLockout";
     scheduleStateOrCrash(SessionState::RESETTING_LOCKOUT);
 
-    mWorker->schedule(Callable::from([this, cookie, hat] {
-        enterStateOrCrash(cookie, SessionState::RESETTING_LOCKOUT);
+    mWorker->schedule(Callable::from([this, hat] {
+        enterStateOrCrash(SessionState::RESETTING_LOCKOUT);
         mEngine->resetLockoutImpl(mCb.get(), hat);
-        enterIdling(cookie);
+        enterIdling();
     }));
 
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus Session::close(int32_t /*cookie*/) {
+ndk::ScopedAStatus Session::close() {
     LOG(INFO) << "close";
-    CHECK(mCurrentState == SessionState::IDLING) << "Can't close a non-idling session. Crashing.";
+    // TODO(b/166800618): call enterIdling from the terminal callbacks and restore this check.
+    // CHECK(mCurrentState == SessionState::IDLING) << "Can't close a non-idling session.
+    // Crashing.";
     mCurrentState = SessionState::CLOSED;
     mCb->onSessionClosed();
     return ndk::ScopedAStatus::ok();
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
index 42e1aa5..6667f7a 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
@@ -37,7 +37,7 @@
         cb->onEnrollmentProgress(0 /* enrollmentId */, 0 /* remaining */);
     }
 
-    void authenticateImpl(ISessionCallback* cb, int64_t /*operationId*/) {
+    void authenticateImpl(ISessionCallback* cb, int64_t /* operationId */) {
         LOG(INFO) << "authenticateImpl";
         cb->onAuthenticationSucceeded(0 /* enrollmentId */, {} /* hat */);
     }
diff --git a/biometrics/fingerprint/aidl/default/include/Session.h b/biometrics/fingerprint/aidl/default/include/Session.h
index 97d5645..9e46422 100644
--- a/biometrics/fingerprint/aidl/default/include/Session.h
+++ b/biometrics/fingerprint/aidl/default/include/Session.h
@@ -27,37 +27,50 @@
 namespace common = aidl::android::hardware::biometrics::common;
 namespace keymaster = aidl::android::hardware::keymaster;
 
+enum class SessionState {
+    IDLING,
+    CLOSED,
+    GENERATING_CHALLENGE,
+    REVOKING_CHALLENGE,
+    ENROLLING,
+    AUTHENTICATING,
+    DETECTING_INTERACTION,
+    ENUMERATING_ENROLLMENTS,
+    REMOVING_ENROLLMENTS,
+    GETTING_AUTHENTICATOR_ID,
+    INVALIDATING_AUTHENTICATOR_ID,
+    RESETTING_LOCKOUT,
+};
+
 class Session : public BnSession {
   public:
     Session(int sensorId, int userId, std::shared_ptr<ISessionCallback> cb,
             FakeFingerprintEngine* engine, WorkerThread* worker);
 
-    ndk::ScopedAStatus generateChallenge(int32_t cookie) override;
+    ndk::ScopedAStatus generateChallenge() override;
 
-    ndk::ScopedAStatus revokeChallenge(int32_t cookie, int64_t challenge) override;
+    ndk::ScopedAStatus revokeChallenge(int64_t challenge) override;
 
-    ndk::ScopedAStatus enroll(int32_t cookie, const keymaster::HardwareAuthToken& hat,
+    ndk::ScopedAStatus enroll(const keymaster::HardwareAuthToken& hat,
                               std::shared_ptr<common::ICancellationSignal>* out) override;
 
-    ndk::ScopedAStatus authenticate(int32_t cookie, int64_t operationId,
+    ndk::ScopedAStatus authenticate(int64_t operationId,
                                     std::shared_ptr<common::ICancellationSignal>* out) override;
 
     ndk::ScopedAStatus detectInteraction(
-            int32_t cookie, std::shared_ptr<common::ICancellationSignal>* out) override;
+            std::shared_ptr<common::ICancellationSignal>* out) override;
 
-    ndk::ScopedAStatus enumerateEnrollments(int32_t cookie) override;
+    ndk::ScopedAStatus enumerateEnrollments() override;
 
-    ndk::ScopedAStatus removeEnrollments(int32_t cookie,
-                                         const std::vector<int32_t>& enrollmentIds) override;
+    ndk::ScopedAStatus removeEnrollments(const std::vector<int32_t>& enrollmentIds) override;
 
-    ndk::ScopedAStatus getAuthenticatorId(int32_t cookie) override;
+    ndk::ScopedAStatus getAuthenticatorId() override;
 
-    ndk::ScopedAStatus invalidateAuthenticatorId(int32_t cookie) override;
+    ndk::ScopedAStatus invalidateAuthenticatorId() override;
 
-    ndk::ScopedAStatus resetLockout(int32_t cookie,
-                                    const keymaster::HardwareAuthToken& hat) override;
+    ndk::ScopedAStatus resetLockout(const keymaster::HardwareAuthToken& hat) override;
 
-    ndk::ScopedAStatus close(int32_t cookie) override;
+    ndk::ScopedAStatus close() override;
 
     ndk::ScopedAStatus onPointerDown(int32_t pointerId, int32_t x, int32_t y, float minor,
                                      float major) override;
@@ -76,11 +89,11 @@
     // Crashes the HAL if the provided state doesn't match the previously scheduled state.
     // Otherwise, transitions into the provided state, clears the scheduled state, and notifies
     // the client about the transition by calling ISessionCallback#onStateChanged.
-    void enterStateOrCrash(int cookie, SessionState state);
+    void enterStateOrCrash(SessionState state);
 
     // Sets the current state to SessionState::IDLING and notifies the client about the transition
     // by calling ISessionCallback#onStateChanged.
-    void enterIdling(int cookie);
+    void enterIdling();
 
     // The sensor and user IDs for which this session was created.
     int32_t mSensorId;
diff --git a/biometrics/fingerprint/aidl/vts/Android.bp b/biometrics/fingerprint/aidl/vts/Android.bp
index 0d83e74..5539548 100644
--- a/biometrics/fingerprint/aidl/vts/Android.bp
+++ b/biometrics/fingerprint/aidl/vts/Android.bp
@@ -14,9 +14,13 @@
         "use_libaidlvintf_gtest_helper_static",
     ],
     srcs: ["VtsHalBiometricsFingerprintTargetTest.cpp"],
+    static_libs: [
+        "android.hardware.biometrics.common-V1-ndk_platform",
+        "android.hardware.biometrics.fingerprint-V1-ndk_platform",
+        "android.hardware.keymaster-V3-ndk_platform",
+    ],
     shared_libs: [
         "libbinder_ndk",
-        "android.hardware.biometrics.fingerprint-V1-ndk_platform",
     ],
     test_suites: [
         "general-tests",
diff --git a/biometrics/fingerprint/aidl/vts/VtsHalBiometricsFingerprintTargetTest.cpp b/biometrics/fingerprint/aidl/vts/VtsHalBiometricsFingerprintTargetTest.cpp
index 885f703..f1cfb17 100644
--- a/biometrics/fingerprint/aidl/vts/VtsHalBiometricsFingerprintTargetTest.cpp
+++ b/biometrics/fingerprint/aidl/vts/VtsHalBiometricsFingerprintTargetTest.cpp
@@ -22,46 +22,20 @@
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 
+#include <chrono>
 #include <future>
 
 namespace aidl::android::hardware::biometrics::fingerprint {
 namespace {
 
+using namespace std::literals::chrono_literals;
+
 constexpr int kSensorId = 0;
 constexpr int kUserId = 0;
-constexpr auto kCallbackTimeout = std::chrono::seconds(1);
-
-enum class MethodName {
-    kOnStateChanged,
-};
-
-struct Invocation {
-    MethodName methodName;
-    int32_t cookie;
-    SessionState state;
-};
 
 class SessionCallback : public BnSessionCallback {
   public:
-    explicit SessionCallback() : mIsPromiseValid(false) {}
-
-    void setPromise(std::promise<std::vector<Invocation>>&& promise) {
-        mPromise = std::move(promise);
-        mIsPromiseValid = true;
-    }
-
-    ndk::ScopedAStatus onStateChanged(int32_t cookie, SessionState state) override {
-        Invocation invocation = {};
-        invocation.methodName = MethodName::kOnStateChanged;
-        invocation.cookie = cookie;
-        invocation.state = state;
-        mInvocations.push_back(invocation);
-        if (state == SessionState::IDLING) {
-            assert(mIsPromiseValid);
-            mPromise.set_value(mInvocations);
-        }
-        return ndk::ScopedAStatus::ok();
-    }
+    explicit SessionCallback(std::promise<void>&& promise) : mPromise(std::move(promise)) {}
 
     ndk::ScopedAStatus onChallengeGenerated(int64_t /*challenge*/) override {
         return ndk::ScopedAStatus::ok();
@@ -119,12 +93,13 @@
         return ndk::ScopedAStatus::ok();
     }
 
-    ndk::ScopedAStatus onSessionClosed() override { return ndk::ScopedAStatus::ok(); }
+    ndk::ScopedAStatus onSessionClosed() override {
+        mPromise.set_value();
+        return ndk::ScopedAStatus::ok();
+    }
 
   private:
-    bool mIsPromiseValid;
-    std::vector<Invocation> mInvocations;
-    std::promise<std::vector<Invocation>> mPromise;
+    std::promise<void> mPromise;
 };
 
 class Fingerprint : public testing::TestWithParam<std::string> {
@@ -139,33 +114,26 @@
 };
 
 TEST_P(Fingerprint, AuthenticateTest) {
-    // Prepare the callback
-    std::promise<std::vector<Invocation>> promise;
+    auto promise = std::promise<void>{};
     auto future = promise.get_future();
-    std::shared_ptr<SessionCallback> cb = ndk::SharedRefBase::make<SessionCallback>();
-    cb->setPromise(std::move(promise));
+    // Prepare the callback.
+    auto cb = ndk::SharedRefBase::make<SessionCallback>(std::move(promise));
 
     // Create a session
     std::shared_ptr<ISession> session;
     ASSERT_TRUE(mHal->createSession(kSensorId, kUserId, cb, &session).isOk());
 
     // Call authenticate
-    int32_t cookie = 123;
     std::shared_ptr<common::ICancellationSignal> cancellationSignal;
-    ASSERT_TRUE(session->authenticate(cookie, 0, &cancellationSignal).isOk());
+    ASSERT_TRUE(session->authenticate(-1 /* operationId */, &cancellationSignal).isOk());
 
     // Get the results
-    ASSERT_TRUE(future.wait_for(kCallbackTimeout) == std::future_status::ready);
-    std::vector<Invocation> invocations = future.get();
+    // TODO(b/166799066): test authenticate.
 
     // Close the session
-    ASSERT_TRUE(session->close(0).isOk());
-
-    ASSERT_FALSE(invocations.empty());
-    EXPECT_EQ(invocations.front().methodName, MethodName::kOnStateChanged);
-    EXPECT_EQ(invocations.front().state, SessionState::AUTHENTICATING);
-    EXPECT_EQ(invocations.back().methodName, MethodName::kOnStateChanged);
-    EXPECT_EQ(invocations.back().state, SessionState::IDLING);
+    ASSERT_TRUE(session->close().isOk());
+    auto status = future.wait_for(1s);
+    ASSERT_EQ(status, std::future_status::ready);
 }
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Fingerprint);
diff --git a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
index 76777dc..8ea1ddd 100644
--- a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
+++ b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.cpp
@@ -179,7 +179,7 @@
     bluetooth_cb->SetWaitTimeout(kCallbackNameScoEventReceived,
                                  WAIT_FOR_SCO_DATA_TIMEOUT);
 
-    EXPECT_TRUE(
+    ASSERT_TRUE(
         bluetooth_cb->WaitForCallback(kCallbackNameInitializationComplete)
             .no_timeout);
 
@@ -289,7 +289,7 @@
 void BluetoothHidlTest::handle_no_ops() {
   while (event_queue.size() > 0) {
     hidl_vec<uint8_t> event = event_queue.front();
-    EXPECT_GE(event.size(),
+    ASSERT_GE(event.size(),
               static_cast<size_t>(EVENT_COMMAND_COMPLETE_STATUS_BYTE));
     bool event_is_no_op =
         (event[EVENT_CODE_BYTE] == EVENT_COMMAND_COMPLETE) &&
@@ -327,7 +327,7 @@
         bluetooth_cb->WaitForCallback(kCallbackNameHciEventReceived).no_timeout;
     EXPECT_TRUE(no_timeout || !timeout_is_error);
     if (no_timeout && timeout_is_error) {
-      EXPECT_LT(static_cast<size_t>(0), event_queue.size());
+      ASSERT_LT(static_cast<size_t>(0), event_queue.size());
     }
     if (event_queue.size() == 0) {
       // WaitForCallback timed out.
@@ -343,12 +343,12 @@
   hidl_vec<uint8_t> event = event_queue.front();
   event_queue.pop();
 
-  EXPECT_GT(event.size(),
+  ASSERT_GT(event.size(),
             static_cast<size_t>(EVENT_COMMAND_COMPLETE_STATUS_BYTE));
-  EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
-  EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
-  EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
-  EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+  ASSERT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
+  ASSERT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
+  ASSERT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
+  ASSERT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
 }
 
 // Send the command to read the controller's buffer sizes.
@@ -362,10 +362,10 @@
   hidl_vec<uint8_t> event = event_queue.front();
   event_queue.pop();
 
-  EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
-  EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
-  EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
-  EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+  ASSERT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
+  ASSERT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
+  ASSERT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
+  ASSERT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
 
   max_acl_data_packet_length =
       event[EVENT_COMMAND_COMPLETE_STATUS_BYTE + 1] +
@@ -415,10 +415,10 @@
     size_t compare_length =
         (cmd.size() > static_cast<size_t>(0xff) ? static_cast<size_t>(0xff)
                                                 : cmd.size());
-    EXPECT_GT(event.size(), compare_length + EVENT_FIRST_PAYLOAD_BYTE - 1);
+    ASSERT_GT(event.size(), compare_length + EVENT_FIRST_PAYLOAD_BYTE - 1);
 
-    EXPECT_EQ(EVENT_LOOPBACK_COMMAND, event[EVENT_CODE_BYTE]);
-    EXPECT_EQ(compare_length, event[EVENT_LENGTH_BYTE]);
+    ASSERT_EQ(EVENT_LOOPBACK_COMMAND, event[EVENT_CODE_BYTE]);
+    ASSERT_EQ(compare_length, event[EVENT_LENGTH_BYTE]);
 
     // Don't compare past the end of the event.
     if (compare_length + EVENT_FIRST_PAYLOAD_BYTE > event.size()) {
@@ -455,12 +455,12 @@
     bluetooth->sendScoData(sco_vector);
 
     // Check the loopback of the SCO packet
-    EXPECT_TRUE(bluetooth_cb->WaitForCallback(kCallbackNameScoEventReceived)
+    ASSERT_TRUE(bluetooth_cb->WaitForCallback(kCallbackNameScoEventReceived)
                     .no_timeout);
     hidl_vec<uint8_t> sco_loopback = sco_queue.front();
     sco_queue.pop();
 
-    EXPECT_EQ(sco_packet.size(), sco_loopback.size());
+    ASSERT_EQ(sco_packet.size(), sco_loopback.size());
     size_t successful_bytes = 0;
 
     for (size_t i = 0; i < sco_packet.size(); i++) {
@@ -474,7 +474,7 @@
         break;
       }
     }
-    EXPECT_EQ(sco_packet.size(), successful_bytes + 1);
+    ASSERT_EQ(sco_packet.size(), successful_bytes + 1);
   }
   logger.setTotalBytes(num_packets * size * 2);
 }
@@ -500,26 +500,15 @@
     bluetooth->sendAclData(acl_vector);
 
     // Check the loopback of the ACL packet
-    EXPECT_TRUE(bluetooth_cb->WaitForCallback(kCallbackNameAclEventReceived)
+    ASSERT_TRUE(bluetooth_cb->WaitForCallback(kCallbackNameAclEventReceived)
                     .no_timeout);
     hidl_vec<uint8_t> acl_loopback = acl_queue.front();
     acl_queue.pop();
 
     EXPECT_EQ(acl_packet.size(), acl_loopback.size());
-    size_t successful_bytes = 0;
-
-    for (size_t i = 0; i < acl_packet.size(); i++) {
-      if (acl_packet[i] == acl_loopback[i]) {
-        successful_bytes = i;
-      } else {
-        ALOGE("Miscompare at %d (expected %x, got %x)", static_cast<int>(i),
-              acl_packet[i], acl_loopback[i]);
-        ALOGE("At %d (expected %x, got %x)", static_cast<int>(i + 1),
-              acl_packet[i + 1], acl_loopback[i + 1]);
-        break;
-      }
+    for (size_t i = 0; i < acl_packet.size() && i < acl_loopback.size(); i++) {
+      EXPECT_EQ(acl_packet[i], acl_loopback[i]) << " at byte number " << i;
     }
-    EXPECT_EQ(acl_packet.size(), successful_bytes + 1);
   }
   logger.setTotalBytes(num_packets * size * 2);
 }
@@ -560,22 +549,22 @@
     wait_for_event(false);
     if (event_queue.size() == 0) {
       // Fail if there was no event received or no connections completed.
-      EXPECT_TRUE(command_complete_received);
-      EXPECT_LT(0, connection_event_count);
+      ASSERT_TRUE(command_complete_received);
+      ASSERT_LT(0, connection_event_count);
       return;
     }
     hidl_vec<uint8_t> event = event_queue.front();
     event_queue.pop();
-    EXPECT_GT(event.size(),
+    ASSERT_GT(event.size(),
               static_cast<size_t>(EVENT_COMMAND_COMPLETE_STATUS_BYTE));
     if (event[EVENT_CODE_BYTE] == EVENT_CONNECTION_COMPLETE) {
-      EXPECT_GT(event.size(),
+      ASSERT_GT(event.size(),
                 static_cast<size_t>(EVENT_CONNECTION_COMPLETE_TYPE));
-      EXPECT_EQ(event[EVENT_LENGTH_BYTE],
+      ASSERT_EQ(event[EVENT_LENGTH_BYTE],
                 EVENT_CONNECTION_COMPLETE_PARAM_LENGTH);
       uint8_t connection_type = event[EVENT_CONNECTION_COMPLETE_TYPE];
 
-      EXPECT_TRUE(connection_type == EVENT_CONNECTION_COMPLETE_TYPE_SCO ||
+      ASSERT_TRUE(connection_type == EVENT_CONNECTION_COMPLETE_TYPE_SCO ||
                   connection_type == EVENT_CONNECTION_COMPLETE_TYPE_ACL);
 
       // Save handles
@@ -590,10 +579,10 @@
             event[EVENT_CONNECTION_COMPLETE_TYPE], handle);
       connection_event_count++;
     } else {
-      EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
-      EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
-      EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
-      EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+      ASSERT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
+      ASSERT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
+      ASSERT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
+      ASSERT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
       command_complete_received = true;
     }
   }
@@ -620,15 +609,15 @@
 
   hidl_vec<uint8_t> event = event_queue.front();
   event_queue.pop();
-  EXPECT_GT(event.size(), static_cast<size_t>(EVENT_LOCAL_LMP_VERSION_BYTE));
+  ASSERT_GT(event.size(), static_cast<size_t>(EVENT_LOCAL_LMP_VERSION_BYTE));
 
-  EXPECT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
-  EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
-  EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
-  EXPECT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
+  ASSERT_EQ(EVENT_COMMAND_COMPLETE, event[EVENT_CODE_BYTE]);
+  ASSERT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
+  ASSERT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
+  ASSERT_EQ(HCI_STATUS_SUCCESS, event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
 
-  EXPECT_LE(HCI_MINIMUM_HCI_VERSION, event[EVENT_LOCAL_HCI_VERSION_BYTE]);
-  EXPECT_LE(HCI_MINIMUM_LMP_VERSION, event[EVENT_LOCAL_LMP_VERSION_BYTE]);
+  ASSERT_LE(HCI_MINIMUM_HCI_VERSION, event[EVENT_LOCAL_HCI_VERSION_BYTE]);
+  ASSERT_LE(HCI_MINIMUM_LMP_VERSION, event[EVENT_LOCAL_LMP_VERSION_BYTE]);
 }
 
 // Send an unknown HCI command and wait for the error message.
@@ -642,18 +631,18 @@
   hidl_vec<uint8_t> event = event_queue.front();
   event_queue.pop();
 
-  EXPECT_GT(event.size(),
+  ASSERT_GT(event.size(),
             static_cast<size_t>(EVENT_COMMAND_COMPLETE_STATUS_BYTE));
   if (event[EVENT_CODE_BYTE] == EVENT_COMMAND_COMPLETE) {
-    EXPECT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
-    EXPECT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
-    EXPECT_EQ(HCI_STATUS_UNKNOWN_HCI_COMMAND,
+    ASSERT_EQ(cmd[0], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE]);
+    ASSERT_EQ(cmd[1], event[EVENT_COMMAND_COMPLETE_OPCODE_LSBYTE + 1]);
+    ASSERT_EQ(HCI_STATUS_UNKNOWN_HCI_COMMAND,
               event[EVENT_COMMAND_COMPLETE_STATUS_BYTE]);
   } else {
-    EXPECT_EQ(EVENT_COMMAND_STATUS, event[EVENT_CODE_BYTE]);
-    EXPECT_EQ(cmd[0], event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE]);
-    EXPECT_EQ(cmd[1], event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE + 1]);
-    EXPECT_EQ(HCI_STATUS_UNKNOWN_HCI_COMMAND,
+    ASSERT_EQ(EVENT_COMMAND_STATUS, event[EVENT_CODE_BYTE]);
+    ASSERT_EQ(cmd[0], event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE]);
+    ASSERT_EQ(cmd[1], event[EVENT_COMMAND_STATUS_OPCODE_LSBYTE + 1]);
+    ASSERT_EQ(HCI_STATUS_UNKNOWN_HCI_COMMAND,
               event[EVENT_COMMAND_STATUS_STATUS_BYTE]);
   }
 }
@@ -678,7 +667,7 @@
   // This should work, but breaks on some current platforms.  Figure out how to
   // grandfather older devices but test new ones.
   if (0 && sco_connection_handles.size() > 0) {
-    EXPECT_LT(0, max_sco_data_packet_length);
+    ASSERT_LT(0, max_sco_data_packet_length);
     sendAndCheckSCO(1, max_sco_data_packet_length, sco_connection_handles[0]);
     int sco_packets_sent = 1;
     int completed_packets =
@@ -690,7 +679,7 @@
   }
 
   if (acl_connection_handles.size() > 0) {
-    EXPECT_LT(0, max_acl_data_packet_length);
+    ASSERT_LT(0, max_acl_data_packet_length);
     sendAndCheckACL(1, max_acl_data_packet_length, acl_connection_handles[0]);
     int acl_packets_sent = 1;
     int completed_packets =
@@ -715,7 +704,7 @@
   // This should work, but breaks on some current platforms.  Figure out how to
   // grandfather older devices but test new ones.
   if (0 && sco_connection_handles.size() > 0) {
-    EXPECT_LT(0, max_sco_data_packet_length);
+    ASSERT_LT(0, max_sco_data_packet_length);
     sendAndCheckSCO(NUM_SCO_PACKETS_BANDWIDTH, max_sco_data_packet_length,
                     sco_connection_handles[0]);
     int sco_packets_sent = NUM_SCO_PACKETS_BANDWIDTH;
@@ -728,7 +717,7 @@
   }
 
   if (acl_connection_handles.size() > 0) {
-    EXPECT_LT(0, max_acl_data_packet_length);
+    ASSERT_LT(0, max_acl_data_packet_length);
     sendAndCheckACL(NUM_ACL_PACKETS_BANDWIDTH, max_acl_data_packet_length,
                     acl_connection_handles[0]);
     int acl_packets_sent = NUM_ACL_PACKETS_BANDWIDTH;
diff --git a/camera/device/3.7/Android.bp b/camera/device/3.7/Android.bp
index 163f781..be08e91 100644
--- a/camera/device/3.7/Android.bp
+++ b/camera/device/3.7/Android.bp
@@ -16,6 +16,7 @@
         "types.hal",
         "ICameraDevice.hal",
         "ICameraDeviceSession.hal",
+        "ICameraInjectionSession.hal",
     ],
     interfaces: [
         "android.hardware.camera.common@1.0",
@@ -24,6 +25,11 @@
         "android.hardware.camera.device@3.4",
         "android.hardware.camera.device@3.5",
         "android.hardware.camera.device@3.6",
+        "android.hardware.camera.metadata@3.2",
+        "android.hardware.camera.metadata@3.3",
+        "android.hardware.camera.metadata@3.4",
+        "android.hardware.camera.metadata@3.5",
+        "android.hardware.camera.metadata@3.6",
         "android.hardware.graphics.common@1.0",
         "android.hidl.base@1.0",
     ],
diff --git a/camera/device/3.7/ICameraInjectionSession.hal b/camera/device/3.7/ICameraInjectionSession.hal
new file mode 100644
index 0000000..f5797c3
--- /dev/null
+++ b/camera/device/3.7/ICameraInjectionSession.hal
@@ -0,0 +1,85 @@
+/*
+ * 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.camera.device@3.7;
+
+import android.hardware.camera.common@1.0::Status;
+import @3.2::BufferCache;
+import @3.2::CameraMetadata;
+import @3.5::StreamConfiguration;
+import @3.6::HalStreamConfiguration;
+import @3.7::ICameraDeviceSession;
+
+/**
+ * Injection Camera device active session interface.
+ *
+ * When an external camera is injected to replace the internal camera session, the
+ * injection session will be established in camera framework, and then
+ * configureInjectionStreams() will be called to ask the external camera to
+ * configure itself to match the stream configuration of the internal camera.
+ *
+ * Camera framework is responsible to close the injection session once the client
+ * switch back to internal camera streaming.
+ *
+ * If the external camera cannot support the configuration ILLEGAL_ARGUMENT will
+ * be returned.
+ */
+interface ICameraInjectionSession extends @3.7::ICameraDeviceSession {
+    /**
+     * configureInjectionStreams:
+     *
+     * Identical to @3.7::ICameraDeviceSession.configureStreams_3_7, except that:
+     *
+     * @param requestedConfiguration
+     *     The current stream configuration of the internal camera session and
+     *     the injection camera must follow the configuration without overriding
+     *     any part of it.
+     * @param characteristics
+     *     The characteristics of internal camera contains a list of keys so that
+     *     the stream continuity can be maintained after the external camera is
+     *     injected.
+     *
+     * @return status Status code for the operation, one of:
+     *     OK:
+     *         On successful stream configuration.
+     *     INTERNAL_ERROR:
+     *         If there has been a fatal error and the device is no longer
+     *         operational. Only close() can be called successfully by the
+     *         framework after this error is returned.
+     *     ILLEGAL_ARGUMENT:
+     *         If the requested stream configuration is invalid. Some examples
+     *         of invalid stream configurations include:
+     *           - Not including any OUTPUT streams
+     *           - Including streams with unsupported formats, or an unsupported
+     *             size for that format.
+     *           - Including too many output streams of a certain format.
+     *           - Unsupported rotation configuration
+     *           - Stream sizes/formats don't satisfy the
+     *             StreamConfigurationMode requirements
+     *             for non-NORMAL mode, or the requested operation_mode is not
+     *             supported by the HAL.
+     *           - Unsupported usage flag
+     *         The camera service cannot filter out all possible illegal stream
+     *         configurations, since some devices may support more simultaneous
+     *         streams or larger stream resolutions than the minimum required
+     *         for a given camera device hardware level. The HAL must return an
+     *         ILLEGAL_ARGUMENT for any unsupported stream set, and then be
+     *         ready to accept a future valid stream configuration in a later
+     *         configureInjectionStreams call.
+     */
+    configureInjectionStreams(StreamConfiguration requestedConfiguration,
+            CameraMetadata characteristics) generates (Status status);
+};
diff --git a/camera/device/3.7/types.hal b/camera/device/3.7/types.hal
index 9450c2f..6910e65 100644
--- a/camera/device/3.7/types.hal
+++ b/camera/device/3.7/types.hal
@@ -21,6 +21,8 @@
 import @3.4::CaptureRequest;
 import @3.4::Stream;
 
+import android.hardware.camera.metadata@3.6::CameraMetadataEnumAndroidSensorPixelMode;
+
 /**
  * Stream:
  *
@@ -57,6 +59,14 @@
      * usage flag.
      */
     int32_t groupId;
+
+    /**
+     *  The sensor pixel modes used by this stream. This can assist the camera
+     *  HAL in decision making about stream combination support.
+     *  If this is empty, the HAL must assume that this stream will only be used
+     *  with ANDROID_SENSOR_PIXEL_MODE set to ANDROID_SENSOR_PIXEL_MODE_DEFAULT.
+     */
+    vec<CameraMetadataEnumAndroidSensorPixelMode> sensorPixelModesUsed;
 };
 
 /**
diff --git a/camera/metadata/3.6/types.hal b/camera/metadata/3.6/types.hal
index 3472ae9..709cfb3 100644
--- a/camera/metadata/3.6/types.hal
+++ b/camera/metadata/3.6/types.hal
@@ -36,6 +36,43 @@
  * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
  */
 enum CameraMetadataTag : @3.5::CameraMetadataTag {
+    /** android.control.availableHighSpeedVideoConfigurationsMaximumResolution [static, int32[], hidden]
+     *
+     * <p>List of available high speed video size, fps range and max batch size configurations
+     * supported by the camera device, in the format of
+     * (width, height, fps_min, fps_max, batch_size_max),
+     * when ANDROID_SENSOR_PIXEL_MODE is set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS_MAXIMUM_RESOLUTION = android.hardware.camera.metadata@3.5::CameraMetadataTag:ANDROID_CONTROL_END_3_5,
+
+    ANDROID_CONTROL_END_3_6,
+
+    /** android.lens.distortionMaximumResolution [static, float[], public]
+     *
+     * <p>The correction coefficients to correct for this camera device's
+     * radial and tangential lens distortion for a
+     * CaptureRequest with ANDROID_SENSOR_PIXEL_MODE set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_LENS_DISTORTION_MAXIMUM_RESOLUTION = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_LENS_END_3_3,
+
+    /** android.lens.intrinsicCalibrationMaximumResolution [static, float[], public]
+     *
+     * <p>The parameters for this camera device's intrinsic
+     * calibration when ANDROID_SENSOR_PIXEL_MODE is set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_LENS_INTRINSIC_CALIBRATION_MAXIMUM_RESOLUTION,
+
+    ANDROID_LENS_END_3_6,
+
     /** android.scaler.defaultSecureImageSize [static, int32[], public]
      *
      * <p>Default YUV/PRIVATE size to use for requesting secure image buffers.</p>
@@ -50,14 +87,237 @@
      */
     ANDROID_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS,
 
+    /** android.scaler.availableStreamConfigurationsMaximumResolution [static, enum[], ndk_public]
+     *
+     * <p>The available stream configurations that this
+     * camera device supports (i.e. format, width, height, output/input stream) for a
+     * CaptureRequest with ANDROID_SENSOR_PIXEL_MODE set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+
+    /** android.scaler.availableMinFrameDurationsMaximumResolution [static, int64[], ndk_public]
+     *
+     * <p>This lists the minimum frame duration for each
+     * format/size combination when the camera device is sent a CaptureRequest with
+     * ANDROID_SENSOR_PIXEL_MODE set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION,
+
+    /** android.scaler.availableStallDurationsMaximumResolution [static, int64[], ndk_public]
+     *
+     * <p>This lists the maximum stall duration for each
+     * output format/size combination when CaptureRequests are submitted with
+     * ANDROID_SENSOR_PIXEL_MODE set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a></p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_SCALER_AVAILABLE_STALL_DURATIONS_MAXIMUM_RESOLUTION,
+
+    /** android.scaler.availableInputOutputFormatsMapMaximumResolution [static, int32, hidden]
+     *
+     * <p>The mapping of image formats that are supported by this
+     * camera device for input streams, to their corresponding output formats, when
+     * ANDROID_SENSOR_PIXEL_MODE is set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP_MAXIMUM_RESOLUTION,
+
     ANDROID_SCALER_END_3_6,
 
+    /** android.sensor.opaqueRawSizeMaximumResolution [static, int32[], system]
+     *
+     * <p>Size in bytes for all the listed opaque RAW buffer sizes when
+     * ANDROID_SENSOR_PIXEL_MODE is set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_SENSOR_OPAQUE_RAW_SIZE_MAXIMUM_RESOLUTION = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_SENSOR_END,
+
+    /** android.sensor.pixelMode [dynamic, enum, public]
+     *
+     * <p>Switches sensor pixel mode between maximum resolution mode and default mode.</p>
+     */
+    ANDROID_SENSOR_PIXEL_MODE,
+
+    /** android.sensor.rawBinningFactorUsed [dynamic, enum, public]
+     *
+     * <p>Whether <code>RAW</code> images requested have their bayer pattern as described by
+     * ANDROID_SENSOR_INFO_BINNING_FACTOR.</p>
+     *
+     * @see ANDROID_SENSOR_INFO_BINNING_FACTOR
+     */
+    ANDROID_SENSOR_RAW_BINNING_FACTOR_USED,
+
+    ANDROID_SENSOR_END_3_6,
+
+    /** android.sensor.info.activeArraySizeMaximumResolution [static, int32[], public]
+     *
+     * <p>The area of the image sensor which corresponds to active pixels after any geometric
+     * distortion correction has been applied, when the sensor runs in maximum resolution mode.</p>
+     */
+    ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_SENSOR_INFO_END,
+
+    /** android.sensor.info.pixelArraySizeMaximumResolution [static, int32[], public]
+     *
+     * <p>Dimensions of the full pixel array, possibly
+     * including black calibration pixels, when the sensor runs in maximum resolution mode.
+     * Analogous to ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, when ANDROID_SENSOR_PIXEL_MODE is
+     * set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE_MAXIMUM_RESOLUTION,
+
+    /** android.sensor.info.preCorrectionActiveArraySizeMaximumResolution [static, int32[], public]
+     *
+     * <p>The area of the image sensor which corresponds to active pixels prior to the
+     * application of any geometric distortion correction, when the sensor runs in maximum
+     * resolution mode. This key must be used for crop / metering regions, only when
+     * ANDROID_SENSOR_PIXEL_MODE is set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION,
+
+    /** android.sensor.info.binningFactor [static, int32[], public]
+     *
+     * <p>Dimensions of the group of pixels which are under the same color filter.
+     * This specifies the width and height (pair of integers) of the group of pixels which fall
+     * under the same color filter for ULTRA_HIGH_RESOLUTION sensors.</p>
+     */
+    ANDROID_SENSOR_INFO_BINNING_FACTOR,
+
+    ANDROID_SENSOR_INFO_END_3_6,
+
+    /** android.depth.availableDepthStreamConfigurationsMaximumResolution [static, enum[], ndk_public]
+     *
+     * <p>The available depth dataspace stream
+     * configurations that this camera device supports
+     * (i.e. format, width, height, output/input stream) when a CaptureRequest is submitted with
+     * ANDROID_SENSOR_PIXEL_MODE set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION = android.hardware.camera.metadata@3.4::CameraMetadataTag:ANDROID_DEPTH_END_3_4,
+
+    /** android.depth.availableDepthMinFrameDurationsMaximumResolution [static, int64[], ndk_public]
+     *
+     * <p>This lists the minimum frame duration for each
+     * format/size combination for depth output formats when a CaptureRequest is submitted with
+     * ANDROID_SENSOR_PIXEL_MODE set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION,
+
+    /** android.depth.availableDepthStallDurationsMaximumResolution [static, int64[], ndk_public]
+     *
+     * <p>This lists the maximum stall duration for each
+     * output format/size combination for depth streams for CaptureRequests where
+     * ANDROID_SENSOR_PIXEL_MODE is set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS_MAXIMUM_RESOLUTION,
+
+    /** android.depth.availableDynamicDepthStreamConfigurationsMaximumResolution [static, enum[], ndk_public]
+     *
+     * <p>The available dynamic depth dataspace stream
+     * configurations that this camera device supports (i.e. format, width, height,
+     * output/input stream) for CaptureRequests where ANDROID_SENSOR_PIXEL_MODE is set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+
+    /** android.depth.availableDynamicDepthMinFrameDurationsMaximumResolution [static, int64[], ndk_public]
+     *
+     * <p>This lists the minimum frame duration for each
+     * format/size combination for dynamic depth output streams  for CaptureRequests where
+     * ANDROID_SENSOR_PIXEL_MODE is set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION,
+
+    /** android.depth.availableDynamicDepthStallDurationsMaximumResolution [static, int64[], ndk_public]
+     *
+     * <p>This lists the maximum stall duration for each
+     * output format/size combination for dynamic depth streams for CaptureRequests where
+     * ANDROID_SENSOR_PIXEL_MODE is set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS_MAXIMUM_RESOLUTION,
+
+    ANDROID_DEPTH_END_3_6,
+
+    /** android.heic.availableHeicStreamConfigurationsMaximumResolution [static, enum[], ndk_public]
+     *
+     * <p>The available HEIC (ISO/IEC 23008-12) stream
+     * configurations that this camera device supports
+     * (i.e. format, width, height, output/input stream).</p>
+     */
+    ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION = android.hardware.camera.metadata@3.4::CameraMetadataTag:ANDROID_HEIC_END_3_4,
+
+    /** android.heic.availableHeicMinFrameDurationsMaximumResolution [static, int64[], ndk_public]
+     *
+     * <p>This lists the minimum frame duration for each
+     * format/size combination for HEIC output formats for CaptureRequests where
+     * ANDROID_SENSOR_PIXEL_MODE is set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION,
+
+    /** android.heic.availableHeicStallDurationsMaximumResolution [static, int64[], ndk_public]
+     *
+     * <p>This lists the maximum stall duration for each
+     * output format/size combination for HEIC streams for CaptureRequests where
+     * ANDROID_SENSOR_PIXEL_MODE is set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS_MAXIMUM_RESOLUTION,
+
+    ANDROID_HEIC_END_3_6,
+
 };
 
 /*
  * Enumeration definitions for the various entries that need them
  */
 
+/** android.request.availableCapabilities enumeration values added since v3.5
+ * @see ANDROID_REQUEST_AVAILABLE_CAPABILITIES
+ */
+enum CameraMetadataEnumAndroidRequestAvailableCapabilities :
+        @3.5::CameraMetadataEnumAndroidRequestAvailableCapabilities {
+    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR,
+    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_REMOSAIC_REPROCESSING,
+};
+
 /** android.scaler.physicalCameraMultiResolutionStreamConfigurations enumeration values
  * @see ANDROID_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS
  */
@@ -65,3 +325,51 @@
     ANDROID_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS_OUTPUT,
     ANDROID_SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS_INPUT,
 };
+
+/** android.scaler.availableStreamConfigurationsMaximumResolution enumeration values
+ * @see ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION
+ */
+enum CameraMetadataEnumAndroidScalerAvailableStreamConfigurationsMaximumResolution : uint32_t {
+    ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_OUTPUT,
+    ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_INPUT,
+};
+
+/** android.sensor.pixelMode enumeration values
+ * @see ANDROID_SENSOR_PIXEL_MODE
+ */
+enum CameraMetadataEnumAndroidSensorPixelMode : uint32_t {
+    ANDROID_SENSOR_PIXEL_MODE_DEFAULT,
+    ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION,
+};
+
+/** android.sensor.rawBinningFactorUsed enumeration values
+ * @see ANDROID_SENSOR_RAW_BINNING_FACTOR_USED
+ */
+enum CameraMetadataEnumAndroidSensorRawBinningFactorUsed : uint32_t {
+    ANDROID_SENSOR_RAW_BINNING_FACTOR_USED_TRUE,
+    ANDROID_SENSOR_RAW_BINNING_FACTOR_USED_FALSE,
+};
+
+/** android.depth.availableDepthStreamConfigurationsMaximumResolution enumeration values
+ * @see ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION
+ */
+enum CameraMetadataEnumAndroidDepthAvailableDepthStreamConfigurationsMaximumResolution : uint32_t {
+    ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_OUTPUT,
+    ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_INPUT,
+};
+
+/** android.depth.availableDynamicDepthStreamConfigurationsMaximumResolution enumeration values
+ * @see ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION
+ */
+enum CameraMetadataEnumAndroidDepthAvailableDynamicDepthStreamConfigurationsMaximumResolution : uint32_t {
+    ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_OUTPUT,
+    ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_INPUT,
+};
+
+/** android.heic.availableHeicStreamConfigurationsMaximumResolution enumeration values
+ * @see ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION
+ */
+enum CameraMetadataEnumAndroidHeicAvailableHeicStreamConfigurationsMaximumResolution : uint32_t {
+    ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_OUTPUT,
+    ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_INPUT,
+};
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index b2fd402..ed3b1fa 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -125,6 +125,7 @@
 using ::android::hardware::camera::metadata::V3_4::
         CameraMetadataEnumAndroidSensorInfoColorFilterArrangement;
 using ::android::hardware::camera::metadata::V3_4::CameraMetadataTag;
+using ::android::hardware::camera::metadata::V3_6::CameraMetadataEnumAndroidSensorPixelMode;
 using ::android::hardware::camera::provider::V2_4::ICameraProvider;
 using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
 using ::android::hardware::camera::provider::V2_6::CameraIdAndStreamCombination;
@@ -767,6 +768,8 @@
             sp<device::V3_7::ICameraDeviceSession> *session3_7 /*out*/);
     void castDevice(const sp<device::V3_2::ICameraDevice> &device, int32_t deviceVersion,
             sp<device::V3_5::ICameraDevice> *device3_5/*out*/);
+    void castDevice3_7(const sp<device::V3_2::ICameraDevice>& device, int32_t deviceVersion,
+                       sp<device::V3_7::ICameraDevice>* device3_7 /*out*/);
     void createStreamConfiguration(const ::android::hardware::hidl_vec<V3_2::Stream>& streams3_2,
             StreamConfigurationMode configMode,
             ::android::hardware::camera::device::V3_2::StreamConfiguration *config3_2,
@@ -785,6 +788,16 @@
             sp<DeviceCb> *outCb /*out*/,
             uint32_t *jpegBufferSize /*out*/,
             bool *useHalBufManager /*out*/);
+    void configureStreams3_7(const std::string& name, int32_t deviceVersion,
+                             sp<ICameraProvider> provider, PixelFormat format,
+                             sp<device::V3_7::ICameraDeviceSession>* session3_7 /*out*/,
+                             V3_2::Stream* previewStream /*out*/,
+                             device::V3_6::HalStreamConfiguration* halStreamConfig /*out*/,
+                             bool* supportsPartialResults /*out*/,
+                             uint32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
+                             sp<DeviceCb>* outCb /*out*/, uint32_t streamConfigCounter,
+                             bool maxResolution);
+
     void configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
             sp<ICameraProvider> provider,
             const AvailableStream *previewThreshold,
@@ -846,6 +859,10 @@
             hidl_vec<int32_t> streamIds, sp<DeviceCb> cb,
             uint32_t streamConfigCounter = 0);
 
+    void verifyBuffersReturned(sp<device::V3_7::ICameraDeviceSession> session,
+                               hidl_vec<int32_t> streamIds, sp<DeviceCb> cb,
+                               uint32_t streamConfigCounter = 0);
+
     void verifySessionReconfigurationQuery(sp<device::V3_5::ICameraDeviceSession> session3_5,
             camera_metadata* oldSessionParams, camera_metadata* newSessionParams);
 
@@ -853,12 +870,15 @@
 
     static bool isDepthOnly(const camera_metadata_t* staticMeta);
 
-    static Status getAvailableOutputStreams(const camera_metadata_t *staticMeta,
-            std::vector<AvailableStream> &outputStreams,
-            const AvailableStream *threshold = nullptr);
+    static bool isUltraHighResolution(const camera_metadata_t* staticMeta);
+
+    static Status getAvailableOutputStreams(const camera_metadata_t* staticMeta,
+                                            std::vector<AvailableStream>& outputStreams,
+                                            const AvailableStream* threshold = nullptr,
+                                            bool maxResolution = false);
 
     static Status getMaxOutputSizeForFormat(const camera_metadata_t* staticMeta, PixelFormat format,
-                                            Size* size);
+                                            Size* size, bool maxResolution = false);
 
     static Status getMandatoryConcurrentStreams(const camera_metadata_t* staticMeta,
                                                 std::vector<AvailableStream>* outputStreams);
@@ -4841,6 +4861,184 @@
     }
 }
 
+// Generate and verify an ultra high resolution capture request
+TEST_P(CameraHidlTest, processUltraHighResolutionRequest) {
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    uint64_t bufferId = 1;
+    uint32_t frameNumber = 1;
+    ::android::hardware::hidl_vec<uint8_t> settings;
+
+    for (const auto& name : cameraDeviceNames) {
+        int deviceVersion = getCameraDeviceVersion(name, mProviderType);
+        if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_7) {
+            continue;
+        }
+        std::string version, deviceId;
+        ASSERT_TRUE(::matchDeviceName(name, mProviderType, &version, &deviceId));
+        camera_metadata_t* staticMeta;
+        Return<void> ret;
+        sp<ICameraDeviceSession> session;
+        openEmptyDeviceSession(name, mProvider, &session, &staticMeta);
+        if (!isUltraHighResolution(staticMeta)) {
+            free_camera_metadata(staticMeta);
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+        android::hardware::camera::common::V1_0::helper::CameraMetadata defaultSettings;
+        ret = session->constructDefaultRequestSettings(
+                RequestTemplate::STILL_CAPTURE,
+                [&defaultSettings](auto status, const auto& req) mutable {
+                    ASSERT_EQ(Status::OK, status);
+
+                    const camera_metadata_t* metadata =
+                            reinterpret_cast<const camera_metadata_t*>(req.data());
+                    size_t expectedSize = req.size();
+                    int result = validate_camera_metadata_structure(metadata, &expectedSize);
+                    ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+
+                    size_t entryCount = get_camera_metadata_entry_count(metadata);
+                    ASSERT_GT(entryCount, 0u);
+                    defaultSettings = metadata;
+                });
+        ASSERT_TRUE(ret.isOk());
+        uint8_t sensorPixelMode =
+                static_cast<uint8_t>(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION);
+        ASSERT_EQ(::android::OK,
+                  defaultSettings.update(ANDROID_SENSOR_PIXEL_MODE, &sensorPixelMode, 1));
+
+        const camera_metadata_t* settingsBuffer = defaultSettings.getAndLock();
+        settings.setToExternal(
+                reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(settingsBuffer)),
+                get_camera_metadata_size(settingsBuffer));
+
+        free_camera_metadata(staticMeta);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
+        V3_6::HalStreamConfiguration halStreamConfig;
+        bool supportsPartialResults = false;
+        bool useHalBufManager = false;
+        uint32_t partialResultCount = 0;
+        V3_2::Stream previewStream;
+        sp<device::V3_7::ICameraDeviceSession> session3_7;
+        sp<DeviceCb> cb;
+        std::list<PixelFormat> pixelFormats = {PixelFormat::YCBCR_420_888, PixelFormat::RAW16};
+        for (PixelFormat format : pixelFormats) {
+            configureStreams3_7(name, deviceVersion, mProvider, format, &session3_7, &previewStream,
+                                &halStreamConfig, &supportsPartialResults, &partialResultCount,
+                                &useHalBufManager, &cb, 0, /*maxResolution*/ true);
+            ASSERT_NE(session3_7, nullptr);
+
+            std::shared_ptr<ResultMetadataQueue> resultQueue;
+            auto resultQueueRet = session3_7->getCaptureResultMetadataQueue(
+                    [&resultQueue](const auto& descriptor) {
+                        resultQueue = std::make_shared<ResultMetadataQueue>(descriptor);
+                        if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
+                            ALOGE("%s: HAL returns empty result metadata fmq,"
+                                  " not use it",
+                                  __func__);
+                            resultQueue = nullptr;
+                            // Don't use the queue onwards.
+                        }
+                    });
+            ASSERT_TRUE(resultQueueRet.isOk());
+
+            std::vector<hidl_handle> graphicBuffers;
+            graphicBuffers.reserve(halStreamConfig.streams.size());
+            ::android::hardware::hidl_vec<StreamBuffer> outputBuffers;
+            outputBuffers.resize(halStreamConfig.streams.size());
+            InFlightRequest inflightReq = {static_cast<ssize_t>(halStreamConfig.streams.size()),
+                                           false,
+                                           supportsPartialResults,
+                                           partialResultCount,
+                                           std::unordered_set<std::string>(),
+                                           resultQueue};
+
+            size_t k = 0;
+            for (const auto& halStream : halStreamConfig.streams) {
+                hidl_handle buffer_handle;
+                if (useHalBufManager) {
+                    outputBuffers[k] = {halStream.v3_4.v3_3.v3_2.id,
+                                        0,
+                                        buffer_handle,
+                                        BufferStatus::OK,
+                                        nullptr,
+                                        nullptr};
+                } else {
+                    allocateGraphicBuffer(
+                            previewStream.width, previewStream.height,
+                            android_convertGralloc1To0Usage(halStream.v3_4.v3_3.v3_2.producerUsage,
+                                                            halStream.v3_4.v3_3.v3_2.consumerUsage),
+                            halStream.v3_4.v3_3.v3_2.overrideFormat, &buffer_handle);
+                    graphicBuffers.push_back(buffer_handle);
+                    outputBuffers[k] = {halStream.v3_4.v3_3.v3_2.id,
+                                        bufferId,
+                                        buffer_handle,
+                                        BufferStatus::OK,
+                                        nullptr,
+                                        nullptr};
+                    bufferId++;
+                }
+                k++;
+            }
+
+            StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
+            V3_4::CaptureRequest request3_4;
+            request3_4.v3_2.frameNumber = frameNumber;
+            request3_4.v3_2.fmqSettingsSize = 0;
+            request3_4.v3_2.settings = settings;
+            request3_4.v3_2.inputBuffer = emptyInputBuffer;
+            request3_4.v3_2.outputBuffers = outputBuffers;
+            V3_7::CaptureRequest request3_7;
+            request3_7.v3_4 = request3_4;
+            request3_7.inputWidth = 0;
+            request3_7.inputHeight = 0;
+
+            {
+                std::unique_lock<std::mutex> l(mLock);
+                mInflightMap.clear();
+                mInflightMap.add(frameNumber, &inflightReq);
+            }
+
+            Status stat = Status::INTERNAL_ERROR;
+            uint32_t numRequestProcessed = 0;
+            hidl_vec<BufferCache> cachesToRemove;
+            Return<void> returnStatus = session3_7->processCaptureRequest_3_7(
+                    {request3_7}, cachesToRemove,
+                    [&stat, &numRequestProcessed](auto s, uint32_t n) {
+                        stat = s;
+                        numRequestProcessed = n;
+                    });
+            ASSERT_TRUE(returnStatus.isOk());
+            ASSERT_EQ(Status::OK, stat);
+            ASSERT_EQ(numRequestProcessed, 1u);
+
+            {
+                std::unique_lock<std::mutex> l(mLock);
+                while (!inflightReq.errorCodeValid &&
+                       ((0 < inflightReq.numBuffersLeft) || (!inflightReq.haveResultMetadata))) {
+                    auto timeout = std::chrono::system_clock::now() +
+                                   std::chrono::seconds(kStreamBufferTimeoutSec);
+                    ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+                }
+
+                ASSERT_FALSE(inflightReq.errorCodeValid);
+                ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
+            }
+            if (useHalBufManager) {
+                hidl_vec<int32_t> streamIds(halStreamConfig.streams.size());
+                for (size_t i = 0; i < streamIds.size(); i++) {
+                    streamIds[i] = halStreamConfig.streams[i].v3_4.v3_3.v3_2.id;
+                }
+                verifyBuffersReturned(session3_7, streamIds, cb);
+            }
+
+            ret = session3_7->close();
+            ASSERT_TRUE(ret.isOk());
+        }
+    }
+}
+
 // Generate and verify a burst containing alternating sensor sensitivity values
 TEST_P(CameraHidlTest, processCaptureRequestBurstISO) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
@@ -5537,21 +5735,26 @@
 
 // Retrieve all valid output stream resolutions from the camera
 // static characteristics.
-Status CameraHidlTest::getAvailableOutputStreams(const camera_metadata_t *staticMeta,
-        std::vector<AvailableStream> &outputStreams,
-        const AvailableStream *threshold) {
+Status CameraHidlTest::getAvailableOutputStreams(const camera_metadata_t* staticMeta,
+                                                 std::vector<AvailableStream>& outputStreams,
+                                                 const AvailableStream* threshold,
+                                                 bool maxResolution) {
     AvailableStream depthPreviewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
                                              static_cast<int32_t>(PixelFormat::Y16)};
     if (nullptr == staticMeta) {
         return Status::ILLEGAL_ARGUMENT;
     }
+    int scalerTag = maxResolution
+                            ? ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION
+                            : ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS;
+    int depthTag = maxResolution
+                           ? ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION
+                           : ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS;
 
     camera_metadata_ro_entry scalarEntry;
     camera_metadata_ro_entry depthEntry;
-    int foundScalar = find_camera_metadata_ro_entry(staticMeta,
-            ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &scalarEntry);
-    int foundDepth = find_camera_metadata_ro_entry(staticMeta,
-            ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS, &depthEntry);
+    int foundScalar = find_camera_metadata_ro_entry(staticMeta, scalerTag, &scalarEntry);
+    int foundDepth = find_camera_metadata_ro_entry(staticMeta, depthTag, &depthEntry);
     if ((0 != foundScalar || (0 != (scalarEntry.count % 4))) &&
         (0 != foundDepth || (0 != (depthEntry.count % 4)))) {
         return Status::ILLEGAL_ARGUMENT;
@@ -5619,9 +5822,12 @@
 }
 
 Status CameraHidlTest::getMaxOutputSizeForFormat(const camera_metadata_t* staticMeta,
-                                                 PixelFormat format, Size* size) {
+                                                 PixelFormat format, Size* size,
+                                                 bool maxResolution) {
     std::vector<AvailableStream> outputStreams;
-    if (size == nullptr || getAvailableOutputStreams(staticMeta, outputStreams) != Status::OK) {
+    if (size == nullptr ||
+        getAvailableOutputStreams(staticMeta, outputStreams,
+                                  /*threshold*/ nullptr, maxResolution) != Status::OK) {
         return Status::ILLEGAL_ARGUMENT;
     }
     Size maxSize;
@@ -6065,6 +6271,148 @@
     *config3_2 = {streams3_2, configMode};
 }
 
+// Configure streams
+void CameraHidlTest::configureStreams3_7(
+        const std::string& name, int32_t deviceVersion, sp<ICameraProvider> provider,
+        PixelFormat format, sp<device::V3_7::ICameraDeviceSession>* session3_7 /*out*/,
+        V3_2::Stream* previewStream /*out*/,
+        device::V3_6::HalStreamConfiguration* halStreamConfig /*out*/,
+        bool* supportsPartialResults /*out*/, uint32_t* partialResultCount /*out*/,
+        bool* useHalBufManager /*out*/, sp<DeviceCb>* outCb /*out*/, uint32_t streamConfigCounter,
+        bool maxResolution) {
+    ASSERT_NE(nullptr, session3_7);
+    ASSERT_NE(nullptr, halStreamConfig);
+    ASSERT_NE(nullptr, previewStream);
+    ASSERT_NE(nullptr, supportsPartialResults);
+    ASSERT_NE(nullptr, partialResultCount);
+    ASSERT_NE(nullptr, useHalBufManager);
+    ASSERT_NE(nullptr, outCb);
+
+    std::vector<AvailableStream> outputStreams;
+    ::android::sp<ICameraDevice> device3_x;
+    ALOGI("configureStreams: Testing camera device %s", name.c_str());
+    Return<void> ret;
+    ret = provider->getCameraDeviceInterface_V3_x(name, [&](auto status, const auto& device) {
+        ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+        ASSERT_EQ(Status::OK, status);
+        ASSERT_NE(device, nullptr);
+        device3_x = device;
+    });
+    ASSERT_TRUE(ret.isOk());
+
+    camera_metadata_t* staticMeta;
+    ret = device3_x->getCameraCharacteristics([&](Status s, CameraMetadata metadata) {
+        ASSERT_EQ(Status::OK, s);
+        staticMeta =
+                clone_camera_metadata(reinterpret_cast<const camera_metadata_t*>(metadata.data()));
+        ASSERT_NE(nullptr, staticMeta);
+    });
+    ASSERT_TRUE(ret.isOk());
+
+    camera_metadata_ro_entry entry;
+    auto status =
+            find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry);
+    if ((0 == status) && (entry.count > 0)) {
+        *partialResultCount = entry.data.i32[0];
+        *supportsPartialResults = (*partialResultCount > 1);
+    }
+
+    sp<DeviceCb> cb = new DeviceCb(this, deviceVersion, staticMeta);
+    sp<ICameraDeviceSession> session;
+    ret = device3_x->open(cb, [&session](auto status, const auto& newSession) {
+        ALOGI("device::open returns status:%d", (int)status);
+        ASSERT_EQ(Status::OK, status);
+        ASSERT_NE(newSession, nullptr);
+        session = newSession;
+    });
+    ASSERT_TRUE(ret.isOk());
+    *outCb = cb;
+
+    sp<device::V3_3::ICameraDeviceSession> session3_3;
+    sp<device::V3_4::ICameraDeviceSession> session3_4;
+    sp<device::V3_5::ICameraDeviceSession> session3_5;
+    sp<device::V3_6::ICameraDeviceSession> session3_6;
+    castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+                session3_7);
+    ASSERT_NE(nullptr, (*session3_7).get());
+
+    *useHalBufManager = false;
+    status = find_camera_metadata_ro_entry(
+            staticMeta, ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
+    if ((0 == status) && (entry.count == 1)) {
+        *useHalBufManager = (entry.data.u8[0] ==
+                             ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+    }
+
+    outputStreams.clear();
+    Size maxSize;
+    auto rc = getMaxOutputSizeForFormat(staticMeta, format, &maxSize, maxResolution);
+    ASSERT_EQ(Status::OK, rc);
+    free_camera_metadata(staticMeta);
+
+    ::android::hardware::hidl_vec<V3_7::Stream> streams3_7(1);
+    streams3_7[0].groupId = -1;
+    streams3_7[0].sensorPixelModesUsed = {
+            CameraMetadataEnumAndroidSensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION};
+    streams3_7[0].v3_4.bufferSize = 0;
+    streams3_7[0].v3_4.v3_2.id = 0;
+    streams3_7[0].v3_4.v3_2.streamType = StreamType::OUTPUT;
+    streams3_7[0].v3_4.v3_2.width = static_cast<uint32_t>(maxSize.width);
+    streams3_7[0].v3_4.v3_2.height = static_cast<uint32_t>(maxSize.height);
+    streams3_7[0].v3_4.v3_2.format = static_cast<PixelFormat>(format);
+    streams3_7[0].v3_4.v3_2.usage = GRALLOC1_CONSUMER_USAGE_CPU_READ;
+    streams3_7[0].v3_4.v3_2.dataSpace = 0;
+    streams3_7[0].v3_4.v3_2.rotation = StreamRotation::ROTATION_0;
+
+    ::android::hardware::camera::device::V3_7::StreamConfiguration config3_7;
+    config3_7.streams = streams3_7;
+    config3_7.operationMode = StreamConfigurationMode::NORMAL_MODE;
+    config3_7.streamConfigCounter = streamConfigCounter;
+    config3_7.multiResolutionInputImage = false;
+    RequestTemplate reqTemplate = RequestTemplate::STILL_CAPTURE;
+    ret = (*session3_7)
+                  ->constructDefaultRequestSettings(reqTemplate,
+                                                    [&config3_7](auto status, const auto& req) {
+                                                        ASSERT_EQ(Status::OK, status);
+                                                        config3_7.sessionParams = req;
+                                                    });
+    ASSERT_TRUE(ret.isOk());
+
+    ASSERT_TRUE(deviceVersion >= CAMERA_DEVICE_API_VERSION_3_7);
+    sp<device::V3_7::ICameraDevice> cameraDevice3_7 = nullptr;
+    castDevice3_7(device3_x, deviceVersion, &cameraDevice3_7);
+    ASSERT_NE(cameraDevice3_7, nullptr);
+    bool supported = false;
+    ret = cameraDevice3_7->isStreamCombinationSupported_3_7(
+            config3_7, [&supported](Status s, bool combStatus) {
+                ASSERT_TRUE((Status::OK == s) || (Status::METHOD_NOT_SUPPORTED == s));
+                if (Status::OK == s) {
+                    supported = combStatus;
+                }
+            });
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_EQ(supported, true);
+
+    if (*session3_7 != nullptr) {
+        ret = (*session3_7)
+                      ->configureStreams_3_7(
+                              config3_7,
+                              [&](Status s, device::V3_6::HalStreamConfiguration halConfig) {
+                                  ASSERT_EQ(Status::OK, s);
+                                  *halStreamConfig = halConfig;
+                                  if (*useHalBufManager) {
+                                      hidl_vec<V3_4::Stream> streams(1);
+                                      hidl_vec<V3_2::HalStream> halStreams(1);
+                                      streams[0] = streams3_7[0].v3_4;
+                                      halStreams[0] = halConfig.streams[0].v3_4.v3_3.v3_2;
+                                      cb->setCurrentStreamConfig(streams, halStreams);
+                                  }
+                              });
+    }
+    *previewStream = streams3_7[0].v3_4.v3_2;
+    ASSERT_TRUE(ret.isOk());
+}
+
 // Configure multiple preview streams using different physical ids.
 void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
         sp<ICameraProvider> provider,
@@ -6362,6 +6710,21 @@
     ASSERT_TRUE(ret.isOk());
 }
 
+bool CameraHidlTest::isUltraHighResolution(const camera_metadata_t* staticMeta) {
+    camera_metadata_ro_entry scalarEntry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+                                           &scalarEntry);
+    if (rc == 0) {
+        for (uint32_t i = 0; i < scalarEntry.count; i++) {
+            if (scalarEntry.data.u8[i] ==
+                ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
 bool CameraHidlTest::isDepthOnly(const camera_metadata_t* staticMeta) {
     camera_metadata_ro_entry scalarEntry;
     camera_metadata_ro_entry depthEntry;
@@ -6590,6 +6953,17 @@
     ASSERT_TRUE(ret.isOk());
 }
 
+void CameraHidlTest::castDevice3_7(const sp<device::V3_2::ICameraDevice>& device,
+                                   int32_t deviceVersion,
+                                   sp<device::V3_7::ICameraDevice>* device3_7 /*out*/) {
+    ASSERT_NE(nullptr, device3_7);
+    if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_7) {
+        auto castResult = device::V3_7::ICameraDevice::castFrom(device);
+        ASSERT_TRUE(castResult.isOk());
+        *device3_7 = castResult;
+    }
+}
+
 void CameraHidlTest::castDevice(const sp<device::V3_2::ICameraDevice> &device,
         int32_t deviceVersion, sp<device::V3_5::ICameraDevice> *device3_5/*out*/) {
     ASSERT_NE(nullptr, device3_5);
@@ -7303,6 +7677,13 @@
     cb->waitForBuffersReturned();
 }
 
+void CameraHidlTest::verifyBuffersReturned(sp<device::V3_7::ICameraDeviceSession> session3_7,
+                                           hidl_vec<int32_t> streamIds, sp<DeviceCb> cb,
+                                           uint32_t streamConfigCounter) {
+    session3_7->signalStreamFlush(streamIds, /*streamConfigCounter*/ streamConfigCounter);
+    cb->waitForBuffersReturned();
+}
+
 void CameraHidlTest::verifyLogicalCameraResult(const camera_metadata_t* staticMetadata,
         const ::android::hardware::camera::common::V1_0::helper::CameraMetadata& resultMetadata) {
     std::unordered_set<std::string> physicalIds;
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SessionState.aidl b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/Ashmem.aidl
similarity index 77%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SessionState.aidl
copy to common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/Ashmem.aidl
index 9b0b6f6..a438031 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SessionState.aidl
+++ b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/Ashmem.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -31,19 +31,9 @@
 // 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.biometrics.fingerprint;
-@Backing(type="byte") @VintfStability
-enum SessionState {
-  IDLING = 0,
-  CLOSED = 1,
-  GENERATING_CHALLENGE = 2,
-  REVOKING_CHALLENGE = 3,
-  ENROLLING = 4,
-  AUTHENTICATING = 5,
-  DETECTING_INTERACTION = 6,
-  ENUMERATING_ENROLLMENTS = 7,
-  REMOVING_ENROLLMENTS = 8,
-  GETTING_AUTHENTICATOR_ID = 9,
-  INVALIDATING_AUTHENTICATOR_ID = 10,
-  RESETTING_LOCKOUT = 11,
+package android.hardware.common;
+@VintfStability
+parcelable Ashmem {
+  ParcelFileDescriptor fd;
+  long size;
 }
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SessionState.aidl b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MappableFile.aidl
similarity index 77%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SessionState.aidl
copy to common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MappableFile.aidl
index 9b0b6f6..394ea8f 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SessionState.aidl
+++ b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MappableFile.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -31,19 +31,11 @@
 // 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.biometrics.fingerprint;
-@Backing(type="byte") @VintfStability
-enum SessionState {
-  IDLING = 0,
-  CLOSED = 1,
-  GENERATING_CHALLENGE = 2,
-  REVOKING_CHALLENGE = 3,
-  ENROLLING = 4,
-  AUTHENTICATING = 5,
-  DETECTING_INTERACTION = 6,
-  ENUMERATING_ENROLLMENTS = 7,
-  REMOVING_ENROLLMENTS = 8,
-  GETTING_AUTHENTICATOR_ID = 9,
-  INVALIDATING_AUTHENTICATOR_ID = 10,
-  RESETTING_LOCKOUT = 11,
+package android.hardware.common;
+@VintfStability
+parcelable MappableFile {
+  long length;
+  int prot;
+  ParcelFileDescriptor fd;
+  long offset;
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/NativeHandle.aidl b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/NativeHandle.aidl
index f37b7d5..2ed5c0b 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/NativeHandle.aidl
+++ b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/NativeHandle.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// 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 changes to the AIDL files built
+// 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
diff --git a/common/aidl/android/hardware/common/Ashmem.aidl b/common/aidl/android/hardware/common/Ashmem.aidl
new file mode 100644
index 0000000..8e40266
--- /dev/null
+++ b/common/aidl/android/hardware/common/Ashmem.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+package android.hardware.common;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Type that holds same memory as the "ashmem" hidl_memory type from HIDL.
+ */
+@VintfStability
+parcelable Ashmem {
+    /**
+     * A handle to a memory region.
+     */
+    ParcelFileDescriptor fd;
+    /**
+     * Size of the memory region in bytes.
+     */
+    long size;
+}
diff --git a/common/aidl/android/hardware/common/MappableFile.aidl b/common/aidl/android/hardware/common/MappableFile.aidl
new file mode 100644
index 0000000..a7763ea
--- /dev/null
+++ b/common/aidl/android/hardware/common/MappableFile.aidl
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+package android.hardware.common;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * A region of a file that can be mapped into memory.
+ *
+ * In Linux, MappableFile may be used with mmap as `MAP_SHARED`.
+ *
+ * MappableFile is compatible with ::android::base::MappedFile.
+ */
+@VintfStability
+parcelable MappableFile {
+    /**
+     * Length of the mapping region in bytes.
+     */
+    long length;
+    /**
+     * The desired memory protection for the mapping.
+     *
+     * In Linux, prot is either `PROT_NONE` (indicating that mapped pages may not be accessed) or
+     * the bitwise OR of one or more of the following flags:
+     * - `PROT_READ` (indicating that the mapped pages may be read)
+     * - `PROT_WRITE` (indicating that the mapped pages may be written)
+     */
+    int prot;
+    /**
+     * A handle to a mappable file.
+     */
+    ParcelFileDescriptor fd;
+    /**
+     * The offset in the file to the beginning of the mapping region in number of bytes.
+     *
+     * Note: Some mapping functions require that the offset is aligned to the page size.
+     */
+    long offset;
+}
diff --git a/common/support/Android.bp b/common/support/Android.bp
index 8aea306..730798d 100644
--- a/common/support/Android.bp
+++ b/common/support/Android.bp
@@ -18,6 +18,11 @@
         "android.hardware.common-V2-ndk_platform",
         "libcutils",
     ],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.neuralnetworks",
+    ],
+    min_sdk_version: "29",
 }
 
 cc_test {
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 9e99c48..bb22974 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -359,7 +359,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.media.c2</name>
-        <version>1.0-1</version>
+        <version>1.0-2</version>
         <interface>
             <name>IComponentStore</name>
             <regex-instance>default[0-9]*</regex-instance>
@@ -419,7 +419,7 @@
     </hal>
     <hal format="aidl" optional="false">
         <name>android.hardware.power</name>
-        <version>1</version>
+        <version>1-2</version>
         <interface>
             <name>IPower</name>
             <instance>default</instance>
diff --git a/contexthub/1.2/types.hal b/contexthub/1.2/types.hal
index 5033ce8..75122bc 100644
--- a/contexthub/1.2/types.hal
+++ b/contexthub/1.2/types.hal
@@ -35,10 +35,12 @@
     AIRPLANE_MODE,
 
     /**
-     * Indicates if the microphone access was turned off globally by the user,
-     * in which case audio data cannot be used and propagated by CHRE.
+     * Indicates if the microphone access is available for CHRE. Microphone
+     * access is disabled if the user has turned off the microphone as a
+     * privacy setting, in which case audio data cannot be used and propagated
+     * by CHRE.
      */
-    GLOBAL_MIC_DISABLE,
+    MICROPHONE,
 };
 
 struct ContextHubMsg {
diff --git a/contexthub/1.2/vts/functional/VtsHalContexthubV1_2TargetTest.cpp b/contexthub/1.2/vts/functional/VtsHalContexthubV1_2TargetTest.cpp
index 3510c23..9ee40ed 100644
--- a/contexthub/1.2/vts/functional/VtsHalContexthubV1_2TargetTest.cpp
+++ b/contexthub/1.2/vts/functional/VtsHalContexthubV1_2TargetTest.cpp
@@ -131,10 +131,10 @@
     ASSERT_OK(registerCallback_1_2(nullptr));
 }
 
-TEST_P(ContexthubHidlTest, TestOnGlobalMicDisableSettingChanged) {
+TEST_P(ContexthubHidlTest, TestOnMicrophoneSettingChanged) {
     ASSERT_OK(registerCallback_1_2(new ContexthubCallbackV1_2()));
-    hubApi->onSettingChanged_1_2(Setting::GLOBAL_MIC_DISABLE, SettingValue::DISABLED);
-    hubApi->onSettingChanged_1_2(Setting::GLOBAL_MIC_DISABLE, SettingValue::ENABLED);
+    hubApi->onSettingChanged_1_2(Setting::MICROPHONE, SettingValue::DISABLED);
+    hubApi->onSettingChanged_1_2(Setting::MICROPHONE, SettingValue::ENABLED);
     ASSERT_OK(registerCallback_1_2(nullptr));
 }
 
diff --git a/current.txt b/current.txt
index 6c576ca..270880f 100644
--- a/current.txt
+++ b/current.txt
@@ -782,6 +782,8 @@
 f729ee6a5f136b25d79ea6895d24700fce413df555baaecf2c39e4440d15d043 android.hardware.neuralnetworks@1.0::types
 a84f8dac7a9b75de1cc2936a9b429b9b62b32a31ea88ca52c29f98f5ddc0fa95 android.hardware.neuralnetworks@1.2::types
 cd331b92312d16ab89f475c39296abbf539efc4114a8c5c2b136ad99b904ef33 android.hardware.neuralnetworks@1.3::types
+c3fec5bd470984402997f78a74b6511efc4063b270f2bd9ee7b78f48b683a1bb android.hardware.neuralnetworks@1.3::IDevice
+0fdfad62c2ec33b52e6687004e5a1971c02d10b93ee4d26df5ccff7ce032494a android.hardware.neuralnetworks@1.3::IPreparedModel
 e8c86c69c438da8d1549856c1bb3e2d1b8da52722f8235ff49a30f2cce91742c android.hardware.soundtrigger@2.1::ISoundTriggerHwCallback
 b9fbb6e2e061ed0960939d48b785e9700210add1f13ed32ecd688d0f1ca20ef7 android.hardware.renderscript@1.0::types
 0f53d70e1eadf8d987766db4bf6ae2048004682168f4cab118da576787def3fa android.hardware.radio@1.0::types
diff --git a/drm/1.0/default/Android.bp b/drm/1.0/default/Android.bp
index af1c076..cbdab4f 100644
--- a/drm/1.0/default/Android.bp
+++ b/drm/1.0/default/Android.bp
@@ -32,6 +32,7 @@
         "-Werror",
         "-Wextra",
         "-Wall",
+        "-Wthread-safety",
     ],
     shared_libs: [
         "liblog",
@@ -42,7 +43,7 @@
     export_header_lib_headers: [
         "libutils_headers",
     ],
-    export_include_dirs : ["include"]
+    export_include_dirs: ["include"],
 }
 
 soong_config_module_type {
@@ -59,8 +60,8 @@
     soong_config_variables: {
         TARGET_ENABLE_MEDIADRM_64: {
             compile_multilib: "both",
-        }
-    }
+        },
+    },
 }
 
 android_hardware_drm_1_0_multilib {
@@ -69,8 +70,8 @@
     soong_config_variables: {
         TARGET_ENABLE_MEDIADRM_64: {
             compile_multilib: "first",
-        }
-    }
+        },
+    },
 }
 
 cc_defaults {
@@ -98,7 +99,7 @@
     name: "android.hardware.drm@1.0-service",
     defaults: [
         "android.hardware.drm@1.0-multilib-exe",
-        "android.hardware.drm@1.0-service-defaults"
+        "android.hardware.drm@1.0-service-defaults",
     ],
     init_rc: ["android.hardware.drm@1.0-service.rc"],
     srcs: ["service.cpp"],
@@ -110,7 +111,7 @@
     name: "android.hardware.drm@1.0-service-lazy",
     defaults: [
         "android.hardware.drm@1.0-multilib-exe",
-        "android.hardware.drm@1.0-service-defaults"
+        "android.hardware.drm@1.0-service-defaults",
     ],
     overrides: ["android.hardware.drm@1.0-service"],
     init_rc: ["android.hardware.drm@1.0-service-lazy.rc"],
diff --git a/drm/1.0/default/CryptoPlugin.cpp b/drm/1.0/default/CryptoPlugin.cpp
index e6d4e84..8dea7e9 100644
--- a/drm/1.0/default/CryptoPlugin.cpp
+++ b/drm/1.0/default/CryptoPlugin.cpp
@@ -53,6 +53,8 @@
             uint32_t bufferId) {
         sp<IMemory> hidlMemory = mapMemory(base);
 
+        std::lock_guard<std::mutex> shared_buffer_lock(mSharedBufferLock);
+
         // allow mapMemory to return nullptr
         mSharedBufferMap[bufferId] = hidlMemory;
         return Void();
@@ -65,7 +67,7 @@
             const SharedBuffer& source, uint64_t offset,
             const DestinationBuffer& destination,
             decrypt_cb _hidl_cb) {
-
+        std::unique_lock<std::mutex> shared_buffer_lock(mSharedBufferLock);
         if (mSharedBufferMap.find(source.bufferId) == mSharedBufferMap.end()) {
             _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "source decrypt buffer base not set");
             return Void();
@@ -79,7 +81,7 @@
             }
         }
 
-        android::CryptoPlugin::Mode legacyMode;
+        android::CryptoPlugin::Mode legacyMode = android::CryptoPlugin::kMode_Unencrypted;
         switch(mode) {
         case Mode::UNENCRYPTED:
             legacyMode = android::CryptoPlugin::kMode_Unencrypted;
@@ -146,7 +148,10 @@
                 return Void();
             }
 
-            if (destBuffer.offset + destBuffer.size > destBase->getSize()) {
+            size_t totalSize = 0;
+            if (__builtin_add_overflow(destBuffer.offset, destBuffer.size, &totalSize) ||
+                totalSize > destBase->getSize()) {
+                android_errorWriteLog(0x534e4554, "176496353");
                 _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
                 return Void();
             }
@@ -157,7 +162,7 @@
             }
 
             base = static_cast<uint8_t *>(static_cast<void *>(destBase->getPointer()));
-            destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
+            destPtr = static_cast<void*>(base + destination.nonsecureMemory.offset);
         } else if (destination.type == BufferType::NATIVE_HANDLE) {
             if (!secure) {
                 _hidl_cb(Status::BAD_VALUE, 0, "native handle destination must be secure");
@@ -170,6 +175,10 @@
             _hidl_cb(Status::BAD_VALUE, 0, "invalid destination type");
             return Void();
         }
+
+        // release mSharedBufferLock
+        shared_buffer_lock.unlock();
+
         ssize_t result = mLegacyPlugin->decrypt(secure, keyId.data(), iv.data(),
                 legacyMode, legacyPattern, srcPtr, legacySubSamples.get(),
                 subSamples.size(), destPtr, &detailMessage);
diff --git a/drm/1.0/default/CryptoPlugin.h b/drm/1.0/default/CryptoPlugin.h
index 11cc2aa..0d091fa 100644
--- a/drm/1.0/default/CryptoPlugin.h
+++ b/drm/1.0/default/CryptoPlugin.h
@@ -17,11 +17,14 @@
 #ifndef ANDROID_HARDWARE_DRM_V1_0__CRYPTOPLUGIN_H
 #define ANDROID_HARDWARE_DRM_V1_0__CRYPTOPLUGIN_H
 
-#include <android/hidl/memory/1.0/IMemory.h>
+#include <android-base/thread_annotations.h>
 #include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hidl/memory/1.0/IMemory.h>
 #include <hidl/Status.h>
 #include <media/hardware/CryptoAPI.h>
 
+#include <mutex>
+
 namespace android {
 namespace hardware {
 namespace drm {
@@ -60,19 +63,21 @@
     Return<void> setSharedBufferBase(const ::android::hardware::hidl_memory& base,
         uint32_t bufferId) override;
 
-    Return<void> decrypt(bool secure, const hidl_array<uint8_t, 16>& keyId,
-            const hidl_array<uint8_t, 16>& iv, Mode mode, const Pattern& pattern,
-            const hidl_vec<SubSample>& subSamples, const SharedBuffer& source,
-            uint64_t offset, const DestinationBuffer& destination,
-            decrypt_cb _hidl_cb) override;
+    Return<void> decrypt(
+            bool secure, const hidl_array<uint8_t, 16>& keyId, const hidl_array<uint8_t, 16>& iv,
+            Mode mode, const Pattern& pattern, const hidl_vec<SubSample>& subSamples,
+            const SharedBuffer& source, uint64_t offset, const DestinationBuffer& destination,
+            decrypt_cb _hidl_cb) override NO_THREAD_SAFETY_ANALYSIS;  // use unique_lock
 
-private:
+  private:
     android::CryptoPlugin *mLegacyPlugin;
-    std::map<uint32_t, sp<IMemory> > mSharedBufferMap;
+    std::map<uint32_t, sp<IMemory>> mSharedBufferMap GUARDED_BY(mSharedBufferLock);
 
     CryptoPlugin() = delete;
     CryptoPlugin(const CryptoPlugin &) = delete;
     void operator=(const CryptoPlugin &) = delete;
+
+    std::mutex mSharedBufferLock;
 };
 
 }  // namespace implementation
diff --git a/drm/1.2/vts/functional/drm_hal_test.cpp b/drm/1.2/vts/functional/drm_hal_test.cpp
index 0dfff26..2d1068d 100644
--- a/drm/1.2/vts/functional/drm_hal_test.cpp
+++ b/drm/1.2/vts/functional/drm_hal_test.cpp
@@ -172,6 +172,7 @@
 TEST_P(DrmHalTest, OfflineLicenseTest) {
     auto sessionId = openSession();
     hidl_vec<uint8_t> keySetId = loadKeys(sessionId, KeyType::OFFLINE);
+    closeSession(sessionId);
 
     auto res = drmPlugin->getOfflineLicenseKeySetIds(
             [&](Status status, const hidl_vec<KeySetId>& keySetIds) {
@@ -201,8 +202,6 @@
 
     err = drmPlugin->removeOfflineLicense(keySetId);
     EXPECT_EQ(Status::BAD_VALUE, err);
-
-    closeSession(sessionId);
 }
 
 /**
@@ -212,6 +211,8 @@
     auto sessionId = openSession();
     DrmHalVTSVendorModule_V1::ContentConfiguration content = getContent(KeyType::OFFLINE);
     hidl_vec<uint8_t> keySetId = loadKeys(sessionId, content, KeyType::OFFLINE);
+    closeSession(sessionId);
+
     drmPlugin->getOfflineLicenseState(keySetId, checkKeySetIdState<Status::OK, OfflineLicenseState::USABLE>);
 
     hidl_vec<uint8_t> keyRequest = getKeyRequest(keySetId, content, KeyType::RELEASE);
@@ -226,7 +227,6 @@
 
     provideKeyResponse(keySetId, keyResponse);
     drmPlugin->getOfflineLicenseState(keySetId, checkKeySetIdState<Status::BAD_VALUE, OfflineLicenseState::UNKNOWN>);
-    closeSession(sessionId);
 }
 
 /**
diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp
index 9a44eb5..609f59e 100644
--- a/gnss/2.1/default/Android.bp
+++ b/gnss/2.1/default/Android.bp
@@ -33,6 +33,7 @@
         "service.cpp",
     ],
     shared_libs: [
+        "libcutils",
         "libhidlbase",
         "libutils",
         "liblog",
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/BlocklistedSource.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/BlocklistedSource.aidl
index 1a2feb7..a4f0097 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/BlocklistedSource.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/BlocklistedSource.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/CorrelationVector.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/CorrelationVector.aidl
index 9c9a241..b0848bb 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/CorrelationVector.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/CorrelationVector.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/ElapsedRealtime.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/ElapsedRealtime.aidl
index fbcc8a3..7d3baa4 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/ElapsedRealtime.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/ElapsedRealtime.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssClock.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssClock.aidl
index 15fe2e9..c54cc2c 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssClock.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssClock.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssConstellationType.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssConstellationType.aidl
index f873b87..c1fcfcc 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssConstellationType.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssConstellationType.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl
index 9e05db7..ebb5d0b 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMeasurement.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMeasurement.aidl
index bc73bb1..948c540 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMeasurement.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMeasurement.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMultipathIndicator.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMultipathIndicator.aidl
index b9db343..24f45c4 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMultipathIndicator.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssMultipathIndicator.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssPowerStats.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssPowerStats.aidl
index 6676e2e..670244f 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssPowerStats.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssPowerStats.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssSignalType.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssSignalType.aidl
index ba02f72..c2a5b51 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssSignalType.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssSignalType.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
index 10b05a7..f93b496 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl
index 9ad9159..fb0931c 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -37,4 +38,5 @@
   const int CAPABILITY_SATELLITE_BLOCKLIST = 512;
   const int CAPABILITY_CORRELATION_VECTOR = 4096;
   const int CAPABILITY_SATELLITE_PVT = 8192;
+  const int CAPABILITY_MEASUREMENT_CORRECTIONS_FOR_DRIVING = 16384;
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.aidl
index 20dd781..54cd022 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementCallback.aidl
index 93894bf..6e62617 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementCallback.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl
index 07a51ae..24d6f9c 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndication.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndication.aidl
index 1cc7f71..fbf1f6f 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndication.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndication.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndicationCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndicationCallback.aidl
index 01f91dc..bfa787e 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndicationCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPowerIndicationCallback.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsds.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsds.aidl
index 1758792..526ecc8 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsds.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsds.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsdsCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsdsCallback.aidl
index a1af105..2205bc4 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsdsCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsdsCallback.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/PsdsType.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/PsdsType.aidl
index b387121..727bb69 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/PsdsType.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/PsdsType.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatelliteClockInfo.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatelliteClockInfo.aidl
index 4dd45b2..ed23e63 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatelliteClockInfo.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatelliteClockInfo.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePositionEcef.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePositionEcef.aidl
index c96b2e5..e1a20c3 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePositionEcef.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePositionEcef.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePvt.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePvt.aidl
index 95af152..747ee90 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePvt.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatellitePvt.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatelliteVelocityEcef.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatelliteVelocityEcef.aidl
index 558aec9..a571048 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatelliteVelocityEcef.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/SatelliteVelocityEcef.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/gnss/aidl/android/hardware/gnss/GnssMeasurement.aidl b/gnss/aidl/android/hardware/gnss/GnssMeasurement.aidl
index f20cd25..336e927 100644
--- a/gnss/aidl/android/hardware/gnss/GnssMeasurement.aidl
+++ b/gnss/aidl/android/hardware/gnss/GnssMeasurement.aidl
@@ -17,8 +17,8 @@
 package android.hardware.gnss;
 
 import android.hardware.gnss.CorrelationVector;
-import android.hardware.gnss.GnssSignalType;
 import android.hardware.gnss.GnssMultipathIndicator;
+import android.hardware.gnss.GnssSignalType;
 import android.hardware.gnss.SatellitePvt;
 
 /**
@@ -32,41 +32,41 @@
 @VintfStability
 parcelable GnssMeasurement {
     /** Bit mask indicating a valid 'snr' is stored in the GnssMeasurement. */
-    const int HAS_SNR                        = 1 << 0;
+    const int HAS_SNR = 1 << 0;
     /** Bit mask indicating a valid 'carrier frequency' is stored in the GnssMeasurement. */
-    const int HAS_CARRIER_FREQUENCY          = 1 << 9;
+    const int HAS_CARRIER_FREQUENCY = 1 << 9;
     /** Bit mask indicating a valid 'carrier cycles' is stored in the GnssMeasurement. */
-    const int HAS_CARRIER_CYCLES             = 1 << 10;
+    const int HAS_CARRIER_CYCLES = 1 << 10;
     /** Bit mask indicating a valid 'carrier phase' is stored in the GnssMeasurement. */
-    const int HAS_CARRIER_PHASE              = 1 << 11;
+    const int HAS_CARRIER_PHASE = 1 << 11;
     /** Bit mask indicating a valid 'carrier phase uncertainty' is stored in the GnssMeasurement. */
-    const int HAS_CARRIER_PHASE_UNCERTAINTY  = 1 << 12;
+    const int HAS_CARRIER_PHASE_UNCERTAINTY = 1 << 12;
     /** Bit mask indicating a valid automatic gain control is stored in the GnssMeasurement. */
-    const int HAS_AUTOMATIC_GAIN_CONTROL     = 1 << 13;
+    const int HAS_AUTOMATIC_GAIN_CONTROL = 1 << 13;
     /** Bit mask indicating a valid full inter-signal bias is stored in the GnssMeasurement. */
-    const int HAS_FULL_ISB                   = 1 << 16;
+    const int HAS_FULL_ISB = 1 << 16;
     /**
      * Bit mask indicating a valid full inter-signal bias uncertainty is stored in the
      * GnssMeasurement.
      */
-    const int HAS_FULL_ISB_UNCERTAINTY       = 1 << 17;
+    const int HAS_FULL_ISB_UNCERTAINTY = 1 << 17;
     /**
      * Bit mask indicating a valid satellite inter-signal bias is stored in the GnssMeasurement.
      */
-    const int HAS_SATELLITE_ISB              = 1 << 18;
+    const int HAS_SATELLITE_ISB = 1 << 18;
     /**
      * Bit mask indicating a valid satellite inter-signal bias uncertainty is stored in the
      * GnssMeasurement.
      */
-    const int HAS_SATELLITE_ISB_UNCERTAINTY  = 1 << 19;
+    const int HAS_SATELLITE_ISB_UNCERTAINTY = 1 << 19;
     /**
      * Bit mask indicating a valid satellite PVT is stored in the GnssMeasurement.
      */
-    const int HAS_SATELLITE_PVT              = 1 << 20;
+    const int HAS_SATELLITE_PVT = 1 << 20;
     /**
      * Bit mask indicating valid correlation vectors are stored in the GnssMeasurement.
      */
-    const int HAS_CORRELATION_VECTOR         = 1 << 21;
+    const int HAS_CORRELATION_VECTOR = 1 << 21;
 
     /**
      * A bitfield of flags indicating the validity of the fields in this GnssMeasurement. The bit
@@ -132,17 +132,17 @@
      * the received GNSS satellite time value.
      *
      * +---------------------------+--------------------+-----+-----------+--------------------+------+
-     * |                           |GPS/QZSS	        |GLNS |BDS        |GAL                 |SBAS  |
+     * |                           |GPS/QZSS            |GLNS |BDS        |GAL                 |SBAS  |
      * +---------------------------+------+------+------+-----+------+----+------+------+------+------+
      * |State Flag	               |L1    |L5I   |L5Q   |L1OF |B1I   |B1I |E1B   |E1C   |E5AQ  |L1    |
-     * |                           |C/A	  |      |      |     |(D1)  |(D2)|      |      |      |C/A   |
+     * |                           |C/A   |      |      |     |(D1)  |(D2)|      |      |      |C/A   |
      * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
-     * |STATE_UNKNOWN              |0	  |0	 |0	    |0	  |0	 |0   |0     |0     |0	   |0     |
+     * |STATE_UNKNOWN              |0     |0     |0     |0    |0     |0   |0     |0     |0     |0     |
      * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
      * |STATE_CODE_LOCK            |1ms   |1 ms  |1 ms  |1 ms |1 ms  |1 ms|-     |-     |1 ms  |1 ms  |
      * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
      * |STATE_SYMBOL_SYNC          |20ms  |10 ms |1 ms  |10 ms|20 ms |2 ms|4 ms  |4 ms  |1 ms  |2 ms  |
-     * |                           |(opt.)|	     |(opt.)|     |(opt.)|    |(opt.)|(opt.)|(opt.)|      |
+     * |                           |(opt.)|      |(opt.)|     |(opt.)|    |(opt.)|(opt.)|(opt.)|      |
      * |---------------------------+------+------+------+-----+------+----+------+------+------+------+
      * |STATE_BIT_SYNC             |20 ms |20 ms |1 ms  |20 ms|20 ms |-   |8 ms  |-     |1 ms  |4 ms  |
      * |                           |      |      |(opt.)|     |      |    |      |      |(opt.)|      |
@@ -194,24 +194,24 @@
      *   - For E1B and E1C, STATE_SYMBOL_SYNC is optional, because it is implied by
      *     STATE_GAL_E1BC_CODE_LOCK.
      */
-    const int STATE_UNKNOWN                = 0;
-    const int STATE_CODE_LOCK              = 1 << 0;
-    const int STATE_BIT_SYNC               = 1 << 1;
-    const int STATE_SUBFRAME_SYNC          = 1 << 2;
-    const int STATE_TOW_DECODED            = 1 << 3;
-    const int STATE_MSEC_AMBIGUOUS         = 1 << 4;
-    const int STATE_SYMBOL_SYNC            = 1 << 5;
-    const int STATE_GLO_STRING_SYNC        = 1 << 6;
-    const int STATE_GLO_TOD_DECODED        = 1 << 7;
-    const int STATE_BDS_D2_BIT_SYNC        = 1 << 8;
-    const int STATE_BDS_D2_SUBFRAME_SYNC   = 1 << 9;
-    const int STATE_GAL_E1BC_CODE_LOCK     = 1 << 10;
-    const int STATE_GAL_E1C_2ND_CODE_LOCK  = 1 << 11;
-    const int STATE_GAL_E1B_PAGE_SYNC      = 1 << 12;
-    const int STATE_SBAS_SYNC              = 1 << 13;
-    const int STATE_TOW_KNOWN              = 1 << 14;
-    const int STATE_GLO_TOD_KNOWN          = 1 << 15;
-    const int STATE_2ND_CODE_LOCK          = 1 << 16;
+    const int STATE_UNKNOWN = 0;
+    const int STATE_CODE_LOCK = 1 << 0;
+    const int STATE_BIT_SYNC = 1 << 1;
+    const int STATE_SUBFRAME_SYNC = 1 << 2;
+    const int STATE_TOW_DECODED = 1 << 3;
+    const int STATE_MSEC_AMBIGUOUS = 1 << 4;
+    const int STATE_SYMBOL_SYNC = 1 << 5;
+    const int STATE_GLO_STRING_SYNC = 1 << 6;
+    const int STATE_GLO_TOD_DECODED = 1 << 7;
+    const int STATE_BDS_D2_BIT_SYNC = 1 << 8;
+    const int STATE_BDS_D2_SUBFRAME_SYNC = 1 << 9;
+    const int STATE_GAL_E1BC_CODE_LOCK = 1 << 10;
+    const int STATE_GAL_E1C_2ND_CODE_LOCK = 1 << 11;
+    const int STATE_GAL_E1B_PAGE_SYNC = 1 << 12;
+    const int STATE_SBAS_SYNC = 1 << 13;
+    const int STATE_TOW_KNOWN = 1 << 14;
+    const int STATE_GLO_TOD_KNOWN = 1 << 15;
+    const int STATE_2ND_CODE_LOCK = 1 << 16;
 
     /**
      * A bitfield of flags indicating the GnssMeasurementState per satellite sync state. It
@@ -380,7 +380,6 @@
      */
     double pseudorangeRateUncertaintyMps;
 
-
     /**
      * Flags indicating the Accumulated Delta Range's states.
      *
@@ -620,8 +619,10 @@
     double satelliteInterSignalBiasUncertaintyNs;
 
     /**
-     * The GNSS satellite position, velocity and time information at the signal transmission time
-     * receivedSvTimeInNs.
+     * The GNSS satellite position, velocity and time information at the same signal transmission
+     * time receivedSvTimeInNs.
+     *
+     * The position and velocity must be in ECEF coordinates.
      *
      * If the data is available, gnssMeasurementFlags must contain HAS_SATELLITE_PVT.
      */
@@ -635,4 +636,4 @@
      * at equally spaced spatial offsets.
      */
     CorrelationVector[] correlationVectors;
-}
\ No newline at end of file
+}
diff --git a/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
index 8881ea7..aad09ef 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
@@ -16,8 +16,8 @@
 
 package android.hardware.gnss;
 
-import android.hardware.gnss.IGnssPsds;
 import android.hardware.gnss.IGnssConfiguration;
+import android.hardware.gnss.IGnssPsds;
 
 /**
  * This interface is required for the HAL to communicate certain information
@@ -26,15 +26,17 @@
  */
 @VintfStability
 interface IGnssCallback {
-
     /** Capability bit mask indicating that GNSS supports blocklisting satellites */
     const int CAPABILITY_SATELLITE_BLOCKLIST = 1 << 9;
 
     /** Capability bit mask indicating that GNSS supports correlation vector */
-    const int CAPABILITY_CORRELATION_VECTOR =  1 << 12;
+    const int CAPABILITY_CORRELATION_VECTOR = 1 << 12;
 
     /** Capability bit mask indicating that GNSS supports satellite PVT */
-    const int CAPABILITY_SATELLITE_PVT       = 1 << 13;
+    const int CAPABILITY_SATELLITE_PVT = 1 << 13;
+
+    /** Capability bit mask indicating that GNSS supports measurement corrections for driving */
+    const int CAPABILITY_MEASUREMENT_CORRECTIONS_FOR_DRIVING = 1 << 14;
 
     /**
      * Callback to inform framework of the GNSS HAL implementation's capabilities.
diff --git a/gnss/aidl/android/hardware/gnss/SatellitePositionEcef.aidl b/gnss/aidl/android/hardware/gnss/SatellitePositionEcef.aidl
index 4b3615e..febe623 100644
--- a/gnss/aidl/android/hardware/gnss/SatellitePositionEcef.aidl
+++ b/gnss/aidl/android/hardware/gnss/SatellitePositionEcef.aidl
@@ -18,6 +18,9 @@
 
 /**
  * Contains estimates of the satellite position fields in ECEF coordinate frame.
+ *
+ * The satellite position must be defined at the time of transmission of the
+ * signal receivedSvTimeNs.
  */
 @VintfStability
 parcelable SatellitePositionEcef {
@@ -36,4 +39,4 @@
      * It covers satellite position and clock errors projected to the pseudorange measurements.
      */
     double ureMeters;
-}
\ No newline at end of file
+}
diff --git a/gnss/aidl/android/hardware/gnss/SatelliteVelocityEcef.aidl b/gnss/aidl/android/hardware/gnss/SatelliteVelocityEcef.aidl
index 25ece3a..f2d7ab6 100644
--- a/gnss/aidl/android/hardware/gnss/SatelliteVelocityEcef.aidl
+++ b/gnss/aidl/android/hardware/gnss/SatelliteVelocityEcef.aidl
@@ -18,6 +18,9 @@
 
 /**
  * Contains estimates of the satellite velocity fields in the ECEF coordinate frame.
+ *
+ * The satellite velocity must be defined at the time of transmission of the
+ * signal receivedSvTimeNs.
  */
 @VintfStability
 parcelable SatelliteVelocityEcef {
@@ -37,4 +40,4 @@
      * projected to the pseudorange rate measurements.
      */
     double ureRateMps;
-}
\ No newline at end of file
+}
diff --git a/gnss/aidl/default/Android.bp b/gnss/aidl/default/Android.bp
index d363a9f..4cc2b6e 100644
--- a/gnss/aidl/default/Android.bp
+++ b/gnss/aidl/default/Android.bp
@@ -40,6 +40,7 @@
     ],
     shared_libs: [
         "libbase",
+        "libcutils",
         "libbinder_ndk",
         "libhidlbase",
         "libutils",
diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp
index a330c5a..43db873 100644
--- a/gnss/common/utils/default/Android.bp
+++ b/gnss/common/utils/default/Android.bp
@@ -44,6 +44,7 @@
     ],
     export_include_dirs: ["include"],
     shared_libs: [
+        "libcutils",
         "libhidlbase",
         "libutils",
         "android.hardware.gnss@1.0",
diff --git a/gnss/common/utils/default/NmeaFixInfo.cpp b/gnss/common/utils/default/NmeaFixInfo.cpp
index 43e008b..c7ee134 100644
--- a/gnss/common/utils/default/NmeaFixInfo.cpp
+++ b/gnss/common/utils/default/NmeaFixInfo.cpp
@@ -202,8 +202,15 @@
     uint32_t fixId = 0;
     double lastTimeStamp = 0;
     for (const auto& line : nmeaRecords) {
+        if (line.compare(0, strlen(GPGA_RECORD_TAG), GPGA_RECORD_TAG) != 0 &&
+            line.compare(0, strlen(GPRMC_RECORD_TAG), GPRMC_RECORD_TAG) != 0) {
+            continue;
+        }
         std::vector<std::string> sentenceValues;
         splitStr(line, COMMA_SEPARATOR, sentenceValues);
+        if (sentenceValues.size() < MIN_COL_NUM) {
+            continue;
+        }
         double currentTimeStamp = std::stof(sentenceValues[1]);
         // If see a new timestamp, report correct location.
         if ((currentTimeStamp - lastTimeStamp) > TIMESTAMP_EPSILON &&
diff --git a/gnss/common/utils/default/include/NmeaFixInfo.h b/gnss/common/utils/default/include/NmeaFixInfo.h
index 06eae7e..c96eece 100644
--- a/gnss/common/utils/default/include/NmeaFixInfo.h
+++ b/gnss/common/utils/default/include/NmeaFixInfo.h
@@ -32,6 +32,7 @@
 constexpr char LINE_SEPARATOR = '\n';
 constexpr char COMMA_SEPARATOR = ',';
 constexpr double TIMESTAMP_EPSILON = 0.001;
+constexpr int MIN_COL_NUM = 13;
 
 /** Helper class to parse and store the GNSS fix details information. */
 class NmeaFixInfo {
diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
index 4d4ec93..a6e8f58 100644
--- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h
+++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
@@ -28,6 +28,8 @@
 #include <string>
 #include <thread>
 
+#include <cutils/properties.h>
+
 #include "GnssAntennaInfo.h"
 #include "GnssConfiguration.h"
 #include "GnssDebug.h"
@@ -157,9 +159,17 @@
 std::unique_ptr<V2_0::GnssLocation> GnssTemplate<T_IGnss>::getLocationFromHW() {
     char inputBuffer[INPUT_BUFFER_SIZE];
     if (!mHardwareModeChecked) {
-        mGnssFd = open(GNSS_PATH, O_RDWR | O_NONBLOCK);
+        // default using gnss0
+        const char * gnss_dev_path = GNSS_PATH;
+        char devname_value[PROPERTY_VALUE_MAX] = "";
+        if (property_get("debug.location.gnss.devname", devname_value, NULL) > 0) {
+            gnss_dev_path = devname_value;
+            ALOGD("using %s instead of the default %s", gnss_dev_path, GNSS_PATH);
+        }
+
+        mGnssFd = open(gnss_dev_path, O_RDWR | O_NONBLOCK);
         if (mGnssFd == -1) {
-            ALOGW("Failed to open /dev/gnss0 errno: %d", errno);
+            ALOGW("Failed to open %s errno: %d", gnss_dev_path, errno);
         }
         mHardwareModeChecked = true;
     }
@@ -186,6 +196,7 @@
         return nullptr;
     }
     while (true) {
+        memset(inputBuffer, 0, INPUT_BUFFER_SIZE);
         bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE);
         if (bytes_read <= 0) {
             break;
@@ -208,9 +219,14 @@
             auto svStatus = filterBlocklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1());
             this->reportSvStatus(svStatus);
             auto currentLocation = getLocationFromHW();
-            if (mGnssFd != -1 && currentLocation != nullptr) {
+            if (mGnssFd != -1) {
                 // Only report location if the return from hardware is valid
-                this->reportLocation(*currentLocation);
+                // note that we can not merge these two "if" together, if didn't
+                // get location from hardware, we shouldn't report location, not
+                // report the "default" one.
+                if (currentLocation != nullptr) {
+                    this->reportLocation(*currentLocation);
+                }
             } else {
                 if (sGnssCallback_2_1 != nullptr || sGnssCallback_2_0 != nullptr) {
                     const auto location = Utils::getMockLocationV2_0();
@@ -249,6 +265,7 @@
     if (mGnssFd != -1) {
         close(mGnssFd);
         mGnssFd = -1;
+        mHardwareModeChecked = false;
     }
     return true;
 }
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index 2a46f9d..cadd13c 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -34,6 +34,7 @@
             apex_available: [
                 "//apex_available:platform",
                 "com.android.media.swcodec",
+                "com.android.neuralnetworks",
             ],
             min_sdk_version: "29",
         },
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
index 3d74af4..46f5d6e 100644
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
@@ -98,7 +98,7 @@
                      // display change and thus the framework may want to reallocate buffers. We
                      // need to free all cached handles, since they are holding a strong reference
                      // to the underlying buffers.
-                     cleanDisplayResources(display);
+                     cleanDisplayResources(display, mResources, mHal);
                      mResources->removeDisplay(display);
                  }
                  mResources->addPhysicalDisplay(display);
@@ -125,56 +125,6 @@
          Hal* const mHal;
          const sp<IComposerCallback> mCallback;
          ComposerResources* const mResources;
-
-         void cleanDisplayResources(Display display) {
-             size_t cacheSize;
-             Error err = mResources->getDisplayClientTargetCacheSize(display, &cacheSize);
-             if (err == Error::NONE) {
-                 for (int slot = 0; slot < cacheSize; slot++) {
-                     ComposerResources::ReplacedHandle replacedBuffer(/*isBuffer*/ true);
-                     // Replace the buffer slots with NULLs. Keep the old handle until it is
-                     // replaced in ComposerHal, otherwise we risk leaving a dangling pointer.
-                     const native_handle_t* clientTarget = nullptr;
-                     err = mResources->getDisplayClientTarget(display, slot, /*useCache*/ true,
-                                                              /*rawHandle*/ nullptr, &clientTarget,
-                                                              &replacedBuffer);
-                     if (err != Error::NONE) {
-                         continue;
-                     }
-                     const std::vector<hwc_rect_t> damage;
-                     err = mHal->setClientTarget(display, clientTarget, /*fence*/ -1, 0, damage);
-                     ALOGE_IF(err != Error::NONE,
-                              "Can't clean slot %d of the client target buffer"
-                              "cache for display %" PRIu64,
-                              slot, display);
-                 }
-             } else {
-                 ALOGE("Can't clean client target cache for display %" PRIu64, display);
-             }
-
-             err = mResources->getDisplayOutputBufferCacheSize(display, &cacheSize);
-             if (err == Error::NONE) {
-                 for (int slot = 0; slot < cacheSize; slot++) {
-                     // Replace the buffer slots with NULLs. Keep the old handle until it is
-                     // replaced in ComposerHal, otherwise we risk leaving a dangling pointer.
-                     ComposerResources::ReplacedHandle replacedBuffer(/*isBuffer*/ true);
-                     const native_handle_t* outputBuffer = nullptr;
-                     err = mResources->getDisplayOutputBuffer(display, slot, /*useCache*/ true,
-                                                              /*rawHandle*/ nullptr, &outputBuffer,
-                                                              &replacedBuffer);
-                     if (err != Error::NONE) {
-                         continue;
-                     }
-                     err = mHal->setOutputBuffer(display, outputBuffer, /*fence*/ -1);
-                     ALOGE_IF(err != Error::NONE,
-                              "Can't clean slot %d of the output buffer cache"
-                              "for display %" PRIu64,
-                              slot, display);
-                 }
-             } else {
-                 ALOGE("Can't clean output buffer cache for display %" PRIu64, display);
-             }
-         }
     };
 
     Return<void> registerCallback(const sp<IComposerCallback>& callback) override {
@@ -380,6 +330,57 @@
         return std::make_unique<ComposerCommandEngine>(mHal, mResources.get());
     }
 
+    static void cleanDisplayResources(Display display, ComposerResources* const resources,
+                                      Hal* const hal) {
+        size_t cacheSize;
+        Error err = resources->getDisplayClientTargetCacheSize(display, &cacheSize);
+        if (err == Error::NONE) {
+            for (int slot = 0; slot < cacheSize; slot++) {
+                ComposerResources::ReplacedHandle replacedBuffer(/*isBuffer*/ true);
+                // Replace the buffer slots with NULLs. Keep the old handle until it is
+                // replaced in ComposerHal, otherwise we risk leaving a dangling pointer.
+                const native_handle_t* clientTarget = nullptr;
+                err = resources->getDisplayClientTarget(display, slot, /*useCache*/ true,
+                                                        /*rawHandle*/ nullptr, &clientTarget,
+                                                        &replacedBuffer);
+                if (err != Error::NONE) {
+                    continue;
+                }
+                const std::vector<hwc_rect_t> damage;
+                err = hal->setClientTarget(display, clientTarget, /*fence*/ -1, 0, damage);
+                ALOGE_IF(err != Error::NONE,
+                         "Can't clean slot %d of the client target buffer"
+                         "cache for display %" PRIu64,
+                         slot, display);
+            }
+        } else {
+            ALOGE("Can't clean client target cache for display %" PRIu64, display);
+        }
+
+        err = resources->getDisplayOutputBufferCacheSize(display, &cacheSize);
+        if (err == Error::NONE) {
+            for (int slot = 0; slot < cacheSize; slot++) {
+                // Replace the buffer slots with NULLs. Keep the old handle until it is
+                // replaced in ComposerHal, otherwise we risk leaving a dangling pointer.
+                ComposerResources::ReplacedHandle replacedBuffer(/*isBuffer*/ true);
+                const native_handle_t* outputBuffer = nullptr;
+                err = resources->getDisplayOutputBuffer(display, slot, /*useCache*/ true,
+                                                        /*rawHandle*/ nullptr, &outputBuffer,
+                                                        &replacedBuffer);
+                if (err != Error::NONE) {
+                    continue;
+                }
+                err = hal->setOutputBuffer(display, outputBuffer, /*fence*/ -1);
+                ALOGE_IF(err != Error::NONE,
+                         "Can't clean slot %d of the output buffer cache"
+                         "for display %" PRIu64,
+                         slot, display);
+            }
+        } else {
+            ALOGE("Can't clean output buffer cache for display %" PRIu64, display);
+        }
+    }
+
     void destroyResources() {
         // We want to call hwc2_close here (and move hwc2_open to the
         // constructor), with the assumption that hwc2_close would
diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
index b179f35..19f5e8c 100644
--- a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
@@ -15,6 +15,8 @@
  */
 
 #include <composer-vts/2.2/ReadbackVts.h>
+#include <composer-vts/2.2/RenderEngineVts.h>
+#include "renderengine/ExternalTexture.h"
 
 namespace android {
 namespace hardware {
@@ -257,10 +259,11 @@
 }
 
 TestBufferLayer::TestBufferLayer(const std::shared_ptr<ComposerClient>& client,
-                                 const std::shared_ptr<Gralloc>& gralloc, Display display,
-                                 int32_t width, int32_t height, PixelFormat format,
+                                 const std::shared_ptr<Gralloc>& gralloc,
+                                 TestRenderEngine& renderEngine, Display display, int32_t width,
+                                 int32_t height, PixelFormat format,
                                  IComposerClient::Composition composition)
-    : TestLayer{client, display} {
+    : TestLayer{client, display}, mRenderEngine(renderEngine) {
     mGralloc = gralloc;
     mComposition = composition;
     mWidth = width;
@@ -293,9 +296,11 @@
 
 LayerSettings TestBufferLayer::toRenderEngineLayerSettings() {
     LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings();
-    layerSettings.source.buffer.buffer =
+    layerSettings.source.buffer.buffer = std::make_shared<renderengine::ExternalTexture>(
             new GraphicBuffer(mBufferHandle, GraphicBuffer::CLONE_HANDLE, mWidth, mHeight,
-                              static_cast<int32_t>(mFormat), 1, mUsage, mStride);
+                              static_cast<int32_t>(mFormat), 1, mUsage, mStride),
+            mRenderEngine.getInternalRenderEngine(),
+            renderengine::ExternalTexture::Usage::READABLE);
 
     layerSettings.source.buffer.usePremultipliedAlpha =
             mBlendMode == IComposerClient::BlendMode::PREMULTIPLIED;
diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
index 3becace..f78dda2 100644
--- a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -69,7 +69,9 @@
                    [](renderengine::LayerSettings& settings) -> renderengine::LayerSettings* {
                        return &settings;
                    });
-    mRenderEngine->drawLayers(mDisplaySettings, compositionLayerPointers, mGraphicBuffer, true,
+    auto texture = std::make_shared<renderengine::ExternalTexture>(
+            mGraphicBuffer, *mRenderEngine, renderengine::ExternalTexture::Usage::WRITEABLE);
+    mRenderEngine->drawLayers(mDisplaySettings, compositionLayerPointers, texture, true,
                               std::move(bufferFence), &readyFence);
     int fd = readyFence.release();
     if (fd != -1) {
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
index d5eedf1..b24e3b6 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
@@ -50,6 +50,8 @@
 static const IComposerClient::Color GREEN = {0, 0xff, 0, 0xff};
 static const IComposerClient::Color BLUE = {0, 0, 0xff, 0xff};
 
+class TestRenderEngine;
+
 class TestLayer {
   public:
     TestLayer(const std::shared_ptr<ComposerClient>& client, Display display)
@@ -110,7 +112,8 @@
   public:
     TestBufferLayer(
             const std::shared_ptr<ComposerClient>& client, const std::shared_ptr<Gralloc>& gralloc,
-            Display display, int32_t width, int32_t height, PixelFormat format,
+            TestRenderEngine& renderEngine, Display display, int32_t width, int32_t height,
+            PixelFormat format,
             IComposerClient::Composition composition = IComposerClient::Composition::DEVICE);
 
     ~TestBufferLayer();
@@ -138,6 +141,7 @@
   protected:
     IComposerClient::Composition mComposition;
     std::shared_ptr<Gralloc> mGralloc;
+    TestRenderEngine& mRenderEngine;
     int32_t mFillFence;
     const native_handle_t* mBufferHandle = nullptr;
 };
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
index f2d5f19..26027d3 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
@@ -14,9 +14,12 @@
  * limitations under the License.
  */
 
+#pragma once
+
 #include <composer-vts/2.2/ReadbackVts.h>
 #include <math/half.h>
 #include <math/vec3.h>
+#include <renderengine/ExternalTexture.h>
 #include <renderengine/RenderEngine.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/GraphicBufferAllocator.h>
@@ -51,12 +54,15 @@
     void drawLayers();
     void checkColorBuffer(std::vector<V2_2::IComposerClient::Color>& expectedColors);
 
+    renderengine::RenderEngine& getInternalRenderEngine() { return *mRenderEngine; }
+
   private:
     common::V1_1::PixelFormat mFormat;
     std::vector<renderengine::LayerSettings> mCompositionLayers;
     std::unique_ptr<renderengine::RenderEngine> mRenderEngine;
     std::vector<renderengine::LayerSettings> mRenderLayers;
     sp<GraphicBuffer> mGraphicBuffer;
+
     DisplaySettings mDisplaySettings;
 };
 
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index 1463c3b..8d52173 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -288,9 +288,9 @@
                                        {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
                                        BLUE);
 
-        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
-                                                       mDisplayWidth, mDisplayHeight,
-                                                       PixelFormat::RGBA_8888);
+        auto layer = std::make_shared<TestBufferLayer>(
+                mComposerClient, mGralloc, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
+                mDisplayHeight, PixelFormat::RGBA_8888);
         layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
         layer->setZOrder(10);
         layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
@@ -422,9 +422,9 @@
                                        {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
                                        BLUE);
 
-        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
-                                                       mDisplayWidth, mDisplayHeight,
-                                                       PixelFormat::RGBA_FP16);
+        auto layer = std::make_shared<TestBufferLayer>(
+                mComposerClient, mGralloc, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
+                mDisplayHeight, PixelFormat::RGBA_FP16);
         layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
         layer->setZOrder(10);
         layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
@@ -538,8 +538,8 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         auto deviceLayer = std::make_shared<TestBufferLayer>(
-                mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, mDisplayHeight / 2,
-                PixelFormat::RGBA_8888);
+                mComposerClient, mGralloc, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
+                mDisplayHeight / 2, PixelFormat::RGBA_8888);
         std::vector<IComposerClient::Color> deviceColors(deviceLayer->mWidth *
                                                          deviceLayer->mHeight);
         ReadbackHelper::fillColorsArea(deviceColors, deviceLayer->mWidth,
@@ -575,8 +575,8 @@
         }
 
         auto clientLayer = std::make_shared<TestBufferLayer>(
-                mComposerClient, mGralloc, mPrimaryDisplay, clientWidth, clientHeight,
-                PixelFormat::RGBA_FP16, IComposerClient::Composition::DEVICE);
+                mComposerClient, mGralloc, *mTestRenderEngine, mPrimaryDisplay, clientWidth,
+                clientHeight, PixelFormat::RGBA_FP16, IComposerClient::Composition::DEVICE);
         IComposerClient::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight};
         clientLayer->setDisplayFrame(clientFrame);
         clientLayer->setZOrder(0);
@@ -657,9 +657,9 @@
         std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
         ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
 
-        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
-                                                       mDisplayWidth, mDisplayHeight,
-                                                       PixelFormat::RGBA_8888);
+        auto layer = std::make_shared<TestBufferLayer>(
+                mComposerClient, mGralloc, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
+                mDisplayHeight, PixelFormat::RGBA_8888);
         layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
         layer->setZOrder(10);
         layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
@@ -805,9 +805,9 @@
                                        {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight},
                                        BLUE);
 
-        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
-                                                       mDisplayWidth, mDisplayHeight,
-                                                       PixelFormat::RGBA_8888);
+        auto layer = std::make_shared<TestBufferLayer>(
+                mComposerClient, mGralloc, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
+                mDisplayHeight, PixelFormat::RGBA_8888);
         layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
         layer->setZOrder(10);
         layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
@@ -957,9 +957,9 @@
         backgroundLayer->setZOrder(0);
         backgroundLayer->setColor(mBackgroundColor);
 
-        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
-                                                       mDisplayWidth, mDisplayHeight,
-                                                       PixelFormat::RGBA_8888);
+        auto layer = std::make_shared<TestBufferLayer>(
+                mComposerClient, mGralloc, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth,
+                mDisplayHeight, PixelFormat::RGBA_8888);
         layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
         layer->setZOrder(10);
         layer->setDataspace(Dataspace::UNKNOWN, mWriter);
@@ -1195,9 +1195,9 @@
         IComposerClient::Rect blueRect = {mSideLength / 2, mSideLength / 2, mSideLength,
                                           mSideLength};
 
-        mLayer =
-            std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
-                                              mSideLength, mSideLength, PixelFormat::RGBA_8888);
+        mLayer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, *mTestRenderEngine,
+                                                   mPrimaryDisplay, mSideLength, mSideLength,
+                                                   PixelFormat::RGBA_8888);
         mLayer->setDisplayFrame({0, 0, mSideLength, mSideLength});
         mLayer->setZOrder(10);
 
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
index c889069..3464342 100644
--- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
@@ -45,12 +45,21 @@
 
     class HalEventCallback : public Hal::EventCallback_2_4 {
       public:
-        HalEventCallback(const sp<IComposerCallback> callback,
+        HalEventCallback(Hal* hal, const sp<IComposerCallback> callback,
                          V2_1::hal::ComposerResources* resources)
-            : mCallback(callback), mResources(resources) {}
+            : mHal(hal), mCallback(callback), mResources(resources) {}
 
         void onHotplug(Display display, IComposerCallback::Connection connected) override {
             if (connected == IComposerCallback::Connection::CONNECTED) {
+                if (mResources->hasDisplay(display)) {
+                    // This is a subsequent hotplug "connected" for a display. This signals a
+                    // display change and thus the framework may want to reallocate buffers. We
+                    // need to free all cached handles, since they are holding a strong reference
+                    // to the underlying buffers.
+                    V2_1::hal::detail::ComposerClientImpl<Interface, Hal>::cleanDisplayResources(
+                            display, mResources, mHal);
+                    mResources->removeDisplay(display);
+                }
                 mResources->addPhysicalDisplay(display);
             } else if (connected == IComposerCallback::Connection::DISCONNECTED) {
                 mResources->removeDisplay(display);
@@ -91,13 +100,15 @@
         }
 
       protected:
+        Hal* const mHal;
         const sp<IComposerCallback> mCallback;
         V2_1::hal::ComposerResources* const mResources;
     };
 
     Return<void> registerCallback_2_4(const sp<IComposerCallback>& callback) override {
         // no locking as we require this function to be called only once
-        mHalEventCallback_2_4 = std::make_unique<HalEventCallback>(callback, mResources.get());
+        mHalEventCallback_2_4 =
+                std::make_unique<HalEventCallback>(mHal, callback, mResources.get());
         mHal->registerEventCallback_2_4(mHalEventCallback_2_4.get());
         return Void();
     }
diff --git a/identity/TEST_MAPPING b/identity/TEST_MAPPING
new file mode 100644
index 0000000..f35f4b7
--- /dev/null
+++ b/identity/TEST_MAPPING
@@ -0,0 +1,13 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsIdentityTestCases"
+    },
+    {
+      "name": "VtsHalIdentityTargetTest"
+    },
+    {
+      "name": "android.hardware.identity-support-lib-test"
+    }
+  ]
+}
diff --git a/identity/aidl/default/Android.bp b/identity/aidl/default/Android.bp
index 05b3662..7c68aee 100644
--- a/identity/aidl/default/Android.bp
+++ b/identity/aidl/default/Android.bp
@@ -31,7 +31,8 @@
     ],
     static_libs: [
         "libbase",
-        "libcppbor",
+        "libcppbor_external",
+        "libcppcose_rkp",
         "libutils",
         "libsoft_attestation_cert",
         "libkeymaster_portable",
@@ -91,7 +92,8 @@
     ],
     static_libs: [
         "libbase",
-        "libcppbor",
+        "libcppbor_external",
+        "libcppcose_rkp",
         "libutils",
         "libsoft_attestation_cert",
         "libkeymaster_portable",
diff --git a/identity/aidl/default/common/IdentityCredential.cpp b/identity/aidl/default/common/IdentityCredential.cpp
index c8ee0dd..95557b5 100644
--- a/identity/aidl/default/common/IdentityCredential.cpp
+++ b/identity/aidl/default/common/IdentityCredential.cpp
@@ -488,7 +488,7 @@
         }
 
         for (size_t n = 0; n < nsMap->size(); n++) {
-            auto [nsKeyItem, nsValueItem] = (*nsMap)[n];
+            auto& [nsKeyItem, nsValueItem] = (*nsMap)[n];
             const cppbor::Tstr* nsKey = nsKeyItem->asTstr();
             const cppbor::Map* nsInnerMap = nsValueItem->asMap();
             if (nsKey == nullptr || nsInnerMap == nullptr) {
diff --git a/identity/aidl/default/common/IdentityCredential.h b/identity/aidl/default/common/IdentityCredential.h
index 9913b86..ef9d133 100644
--- a/identity/aidl/default/common/IdentityCredential.h
+++ b/identity/aidl/default/common/IdentityCredential.h
@@ -27,7 +27,7 @@
 #include <string>
 #include <vector>
 
-#include <cppbor/cppbor.h>
+#include <cppbor.h>
 
 #include "IdentityCredentialStore.h"
 #include "SecureHardwareProxy.h"
diff --git a/identity/aidl/default/common/WritableIdentityCredential.cpp b/identity/aidl/default/common/WritableIdentityCredential.cpp
index 2d897c7..25f129b 100644
--- a/identity/aidl/default/common/WritableIdentityCredential.cpp
+++ b/identity/aidl/default/common/WritableIdentityCredential.cpp
@@ -23,8 +23,8 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 
-#include <cppbor/cppbor.h>
-#include <cppbor/cppbor_parse.h>
+#include <cppbor.h>
+#include <cppbor_parse.h>
 
 #include <utility>
 
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index 82c4011..61d15d2 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -34,7 +34,8 @@
         "libcrypto",
     ],
     static_libs: [
-        "libcppbor",
+        "libcppbor_external",
+        "libcppcose_rkp",
         "libkeymaster_portable",
         "libpuresoftkeymasterdevice",
         "android.hardware.keymaster@4.0",
diff --git a/identity/aidl/vts/AuthenticationKeyTests.cpp b/identity/aidl/vts/AuthenticationKeyTests.cpp
index bda3e70..25d74d4 100644
--- a/identity/aidl/vts/AuthenticationKeyTests.cpp
+++ b/identity/aidl/vts/AuthenticationKeyTests.cpp
@@ -118,7 +118,7 @@
     optional<vector<uint8_t>> proofOfProvisioning =
             support::coseSignGetPayload(proofOfProvisioningSignature);
     ASSERT_TRUE(proofOfProvisioning);
-    string cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {});
+    string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {});
     EXPECT_EQ(
             "[\n"
             "  'ProofOfProvisioning',\n"
diff --git a/identity/aidl/vts/DeleteCredentialTests.cpp b/identity/aidl/vts/DeleteCredentialTests.cpp
index 1d30067..d3addf4 100644
--- a/identity/aidl/vts/DeleteCredentialTests.cpp
+++ b/identity/aidl/vts/DeleteCredentialTests.cpp
@@ -126,7 +126,7 @@
     optional<vector<uint8_t>> proofOfDeletion =
             support::coseSignGetPayload(proofOfDeletionSignature);
     ASSERT_TRUE(proofOfDeletion);
-    string cborPretty = support::cborPrettyPrint(proofOfDeletion.value(), 32, {});
+    string cborPretty = cppbor::prettyPrint(proofOfDeletion.value(), 32, {});
     EXPECT_EQ("['ProofOfDeletion', 'org.iso.18013-5.2019.mdl', true, ]", cborPretty);
     EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfDeletionSignature, {},  // Additional data
                                                  credentialPubKey_));
@@ -153,7 +153,7 @@
     optional<vector<uint8_t>> proofOfDeletion =
             support::coseSignGetPayload(proofOfDeletionSignature);
     ASSERT_TRUE(proofOfDeletion);
-    string cborPretty = support::cborPrettyPrint(proofOfDeletion.value(), 32, {});
+    string cborPretty = cppbor::prettyPrint(proofOfDeletion.value(), 32, {});
     EXPECT_EQ("['ProofOfDeletion', 'org.iso.18013-5.2019.mdl', {0x41, 0x42, 0x43}, true, ]",
               cborPretty);
     EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfDeletionSignature, {},  // Additional data
diff --git a/identity/aidl/vts/EndToEndTests.cpp b/identity/aidl/vts/EndToEndTests.cpp
index 5798b4c..67db915 100644
--- a/identity/aidl/vts/EndToEndTests.cpp
+++ b/identity/aidl/vts/EndToEndTests.cpp
@@ -231,7 +231,7 @@
     optional<vector<uint8_t>> proofOfProvisioning =
             support::coseSignGetPayload(proofOfProvisioningSignature);
     ASSERT_TRUE(proofOfProvisioning);
-    cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
+    cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
     EXPECT_EQ(
             "[\n"
             "  'ProofOfProvisioning',\n"
@@ -339,8 +339,8 @@
     vector<uint8_t> deviceEngagementBytes = deviceEngagement.encode();
     vector<uint8_t> eReaderPubBytes = cppbor::Tstr("ignored").encode();
     cppbor::Array sessionTranscript = cppbor::Array()
-                                              .add(cppbor::Semantic(24, deviceEngagementBytes))
-                                              .add(cppbor::Semantic(24, eReaderPubBytes));
+                                              .add(cppbor::SemanticTag(24, deviceEngagementBytes))
+                                              .add(cppbor::SemanticTag(24, eReaderPubBytes));
     vector<uint8_t> sessionTranscriptEncoded = sessionTranscript.encode();
 
     vector<uint8_t> itemsRequestBytes =
@@ -353,7 +353,7 @@
                                                              .add("Home address", true))
                                 .add("Image", cppbor::Map().add("Portrait image", false)))
                     .encode();
-    cborPretty = support::cborPrettyPrint(itemsRequestBytes, 32, {"EphemeralPublicKey"});
+    cborPretty = cppbor::prettyPrint(itemsRequestBytes, 32, {"EphemeralPublicKey"});
     EXPECT_EQ(
             "{\n"
             "  'nameSpaces' : {\n"
@@ -373,10 +373,10 @@
             cppbor::Array()
                     .add("ReaderAuthentication")
                     .add(sessionTranscript.clone())
-                    .add(cppbor::Semantic(24, itemsRequestBytes))
+                    .add(cppbor::SemanticTag(24, itemsRequestBytes))
                     .encode();
     vector<uint8_t> encodedReaderAuthenticationBytes =
-            cppbor::Semantic(24, encodedReaderAuthentication).encode();
+            cppbor::SemanticTag(24, encodedReaderAuthentication).encode();
     optional<vector<uint8_t>> readerSignature =
             support::coseSignEcDsa(readerKey, {},                     // content
                                    encodedReaderAuthenticationBytes,  // detached content
@@ -443,7 +443,7 @@
     vector<uint8_t> mac;
     vector<uint8_t> deviceNameSpacesEncoded;
     ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
-    cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
+    cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
     ASSERT_EQ(
             "{\n"
             "  'PersonalData' : {\n"
@@ -462,10 +462,11 @@
     string docType = "org.iso.18013-5.2019.mdl";
     optional<vector<uint8_t>> readerEphemeralPrivateKey =
             support::ecKeyPairGetPrivateKey(readerEphemeralKeyPair.value());
-    optional<vector<uint8_t>> eMacKey = support::calcEMacKey(
-            readerEphemeralPrivateKey.value(),                           // Private Key
-            signingPubKey.value(),                                       // Public Key
-            cppbor::Semantic(24, sessionTranscript.encode()).encode());  // SessionTranscriptBytes
+    optional<vector<uint8_t>> eMacKey =
+            support::calcEMacKey(readerEphemeralPrivateKey.value(),  // Private Key
+                                 signingPubKey.value(),              // Public Key
+                                 cppbor::SemanticTag(24, sessionTranscript.encode())
+                                         .encode());  // SessionTranscriptBytes
     optional<vector<uint8_t>> calculatedMac =
             support::calcMac(sessionTranscript.encode(),  // SessionTranscript
                              docType,                     // DocType
@@ -486,7 +487,7 @@
                                 testEntriesEntryCounts)
                         .isOk());
     ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
-    cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
+    cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
     ASSERT_EQ("{}", cborPretty);
     // Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
     calculatedMac = support::calcMac(sessionTranscript.encode(),  // SessionTranscript
@@ -508,7 +509,7 @@
                                 testEntriesEntryCounts)
                         .isOk());
     ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
-    cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
+    cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
     ASSERT_EQ("{}", cborPretty);
     // Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
     calculatedMac = support::calcMac(sessionTranscript.encode(),  // SessionTranscript
diff --git a/identity/aidl/vts/ProveOwnershipTests.cpp b/identity/aidl/vts/ProveOwnershipTests.cpp
index d1a3d39..fa0e293 100644
--- a/identity/aidl/vts/ProveOwnershipTests.cpp
+++ b/identity/aidl/vts/ProveOwnershipTests.cpp
@@ -131,7 +131,7 @@
     optional<vector<uint8_t>> proofOfOwnership =
             support::coseSignGetPayload(proofOfOwnershipSignature);
     ASSERT_TRUE(proofOfOwnership);
-    string cborPretty = support::cborPrettyPrint(proofOfOwnership.value(), 32, {});
+    string cborPretty = cppbor::prettyPrint(proofOfOwnership.value(), 32, {});
     EXPECT_EQ("['ProofOfOwnership', 'org.iso.18013-5.2019.mdl', {0x11, 0x12}, true, ]", cborPretty);
     EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfOwnershipSignature, {},  // Additional data
                                                  credentialPubKey_));
diff --git a/identity/aidl/vts/ReaderAuthTests.cpp b/identity/aidl/vts/ReaderAuthTests.cpp
index 7656c8e..c4a58c3 100644
--- a/identity/aidl/vts/ReaderAuthTests.cpp
+++ b/identity/aidl/vts/ReaderAuthTests.cpp
@@ -262,8 +262,8 @@
     vector<uint8_t> deviceEngagementBytes = deviceEngagement.encode();
     vector<uint8_t> eReaderPubBytes = cppbor::Tstr("ignored").encode();
     cppbor::Array sessionTranscript = cppbor::Array()
-                                              .add(cppbor::Semantic(24, deviceEngagementBytes))
-                                              .add(cppbor::Semantic(24, eReaderPubBytes));
+                                              .add(cppbor::SemanticTag(24, deviceEngagementBytes))
+                                              .add(cppbor::SemanticTag(24, eReaderPubBytes));
     vector<uint8_t> sessionTranscriptBytes = sessionTranscript.encode();
 
     vector<uint8_t> itemsRequestBytes;
@@ -293,10 +293,10 @@
             cppbor::Array()
                     .add("ReaderAuthentication")
                     .add(sessionTranscript.clone())
-                    .add(cppbor::Semantic(24, itemsRequestBytes))
+                    .add(cppbor::SemanticTag(24, itemsRequestBytes))
                     .encode();
     vector<uint8_t> encodedReaderAuthenticationBytes =
-            cppbor::Semantic(24, encodedReaderAuthentication).encode();
+            cppbor::SemanticTag(24, encodedReaderAuthentication).encode();
 
     optional<vector<uint8_t>> readerSignature =
             support::coseSignEcDsa(readerPrivateKey,                  // private key for reader
@@ -517,8 +517,8 @@
     vector<uint8_t> deviceEngagementBytes = deviceEngagement.encode();
     vector<uint8_t> eReaderPubBytes = cppbor::Tstr("ignored").encode();
     cppbor::Array sessionTranscript = cppbor::Array()
-                                              .add(cppbor::Semantic(24, deviceEngagementBytes))
-                                              .add(cppbor::Semantic(24, eReaderPubBytes));
+                                              .add(cppbor::SemanticTag(24, deviceEngagementBytes))
+                                              .add(cppbor::SemanticTag(24, eReaderPubBytes));
     vector<uint8_t> sessionTranscriptBytes = sessionTranscript.encode();
 
     vector<uint8_t> itemsRequestBytes;
@@ -535,10 +535,10 @@
             cppbor::Array()
                     .add("ReaderAuthentication")
                     .add(sessionTranscript.clone())
-                    .add(cppbor::Semantic(24, itemsRequestBytes))
+                    .add(cppbor::SemanticTag(24, itemsRequestBytes))
                     .encode();
     vector<uint8_t> encodedReaderAuthenticationBytes =
-            cppbor::Semantic(24, encodedReaderAuthentication).encode();
+            cppbor::SemanticTag(24, encodedReaderAuthentication).encode();
 
     vector<vector<uint8_t>> readerCertChain = {cert_reader_SelfSigned_};
     optional<vector<uint8_t>> readerSignature =
diff --git a/identity/aidl/vts/TestCredentialTests.cpp b/identity/aidl/vts/TestCredentialTests.cpp
index d53de3b..46c2229 100644
--- a/identity/aidl/vts/TestCredentialTests.cpp
+++ b/identity/aidl/vts/TestCredentialTests.cpp
@@ -114,7 +114,7 @@
     optional<vector<uint8_t>> proofOfProvisioning =
             support::coseSignGetPayload(proofOfProvisioningSignature);
     ASSERT_TRUE(proofOfProvisioning);
-    string cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {});
+    string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {});
     EXPECT_EQ(
             "[\n"
             "  'ProofOfProvisioning',\n"
diff --git a/identity/aidl/vts/UpdateCredentialTests.cpp b/identity/aidl/vts/UpdateCredentialTests.cpp
index 9c5ca55..e05bb3b 100644
--- a/identity/aidl/vts/UpdateCredentialTests.cpp
+++ b/identity/aidl/vts/UpdateCredentialTests.cpp
@@ -114,7 +114,7 @@
     optional<vector<uint8_t>> proofOfProvisioning =
             support::coseSignGetPayload(proofOfProvisioningSignature);
     ASSERT_TRUE(proofOfProvisioning);
-    string cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {});
+    string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {});
     EXPECT_EQ(
             "[\n"
             "  'ProofOfProvisioning',\n"
@@ -195,7 +195,7 @@
     optional<vector<uint8_t>> proofOfProvisioning =
             support::coseSignGetPayload(proofOfProvisioningSignature);
     ASSERT_TRUE(proofOfProvisioning);
-    string cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {});
+    string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {});
     EXPECT_EQ(
             "[\n"
             "  'ProofOfProvisioning',\n"
diff --git a/identity/aidl/vts/UserAuthTests.cpp b/identity/aidl/vts/UserAuthTests.cpp
index ef89d1c..edd1725 100644
--- a/identity/aidl/vts/UserAuthTests.cpp
+++ b/identity/aidl/vts/UserAuthTests.cpp
@@ -160,8 +160,8 @@
     // Let SessionTranscript be a map here (it's an array in EndToEndTest) just
     // to check that the implementation can deal with either.
     cppbor::Map sessionTranscript;
-    sessionTranscript.add(42, cppbor::Semantic(24, deviceEngagementBytes));
-    sessionTranscript.add(43, cppbor::Semantic(24, eReaderPubBytes));
+    sessionTranscript.add(42, cppbor::SemanticTag(24, deviceEngagementBytes));
+    sessionTranscript.add(43, cppbor::SemanticTag(24, eReaderPubBytes));
     return sessionTranscript;
 }
 
@@ -209,7 +209,7 @@
         vector<uint8_t> dataToSign = cppbor::Array()
                                              .add("ReaderAuthentication")
                                              .add(sessionTranscript_.clone())
-                                             .add(cppbor::Semantic(24, itemsRequestBytes))
+                                             .add(cppbor::SemanticTag(24, itemsRequestBytes))
                                              .encode();
     }
 
diff --git a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
index cc63c48..bc37020 100644
--- a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
+++ b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
@@ -338,8 +338,7 @@
     optional<vector<uint8_t>> proofOfProvisioning =
             support::coseSignGetPayload(proofOfProvisioningSignature);
     ASSERT_TRUE(proofOfProvisioning);
-    string cborPretty =
-            support::cborPrettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
+    string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
     EXPECT_EQ(
             "[\n"
             "  'ProofOfProvisioning',\n"
@@ -449,9 +448,9 @@
     optional<vector<uint8_t>> proofOfProvisioning =
             support::coseSignGetPayload(proofOfProvisioningSignature);
     ASSERT_TRUE(proofOfProvisioning);
-    string cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(),
-                                                 32,  //
-                                                 {"readerCertificate"});
+    string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(),
+                                            32,  //
+                                            {"readerCertificate"});
     EXPECT_EQ(
             "[\n"
             "  'ProofOfProvisioning',\n"
diff --git a/identity/support/Android.bp b/identity/support/Android.bp
index d00f59a..db1a945 100644
--- a/identity/support/Android.bp
+++ b/identity/support/Android.bp
@@ -35,6 +35,7 @@
         "android.hardware.keymaster@4.0",
         "libcrypto",
         "libbase",
+        "libcppcose_rkp",
         "libhidlbase",
         "libhardware",
         "libkeymaster_portable",
@@ -42,7 +43,7 @@
         "libpuresoftkeymasterdevice",
     ],
     static_libs: [
-        "libcppbor",
+        "libcppbor_external",
     ],
 }
 
@@ -59,7 +60,7 @@
         "libhardware",
     ],
     static_libs: [
-        "libcppbor",
+        "libcppbor_external",
         "libgmock",
     ],
     test_suites: ["general-tests"],
@@ -89,7 +90,7 @@
         "tests/cppbor_test.cpp",
     ],
     shared_libs: [
-        "libcppbor",
+        "libcppbor_external",
         "libbase",
     ],
     static_libs: [
@@ -104,7 +105,7 @@
         "tests/cppbor_test.cpp",
     ],
     shared_libs: [
-        "libcppbor",
+        "libcppbor_external",
         "libbase",
     ],
     static_libs: [
diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp
index aba89c1..4547624 100644
--- a/identity/support/src/IdentityCredentialSupport.cpp
+++ b/identity/support/src/IdentityCredentialSupport.cpp
@@ -148,199 +148,6 @@
 }
 
 // ---------------------------------------------------------------------------
-// CBOR utilities.
-// ---------------------------------------------------------------------------
-
-static bool cborAreAllElementsNonCompound(const cppbor::CompoundItem* compoundItem) {
-    if (compoundItem->type() == cppbor::ARRAY) {
-        const cppbor::Array* array = compoundItem->asArray();
-        for (size_t n = 0; n < array->size(); n++) {
-            const cppbor::Item* entry = (*array)[n].get();
-            switch (entry->type()) {
-                case cppbor::ARRAY:
-                case cppbor::MAP:
-                    return false;
-                default:
-                    break;
-            }
-        }
-    } else {
-        const cppbor::Map* map = compoundItem->asMap();
-        for (size_t n = 0; n < map->size(); n++) {
-            auto [keyEntry, valueEntry] = (*map)[n];
-            switch (keyEntry->type()) {
-                case cppbor::ARRAY:
-                case cppbor::MAP:
-                    return false;
-                default:
-                    break;
-            }
-            switch (valueEntry->type()) {
-                case cppbor::ARRAY:
-                case cppbor::MAP:
-                    return false;
-                default:
-                    break;
-            }
-        }
-    }
-    return true;
-}
-
-static bool cborPrettyPrintInternal(const cppbor::Item* item, string& out, size_t indent,
-                                    size_t maxBStrSize, const vector<string>& mapKeysToNotPrint) {
-    char buf[80];
-
-    string indentString(indent, ' ');
-
-    switch (item->type()) {
-        case cppbor::UINT:
-            snprintf(buf, sizeof(buf), "%" PRIu64, item->asUint()->unsignedValue());
-            out.append(buf);
-            break;
-
-        case cppbor::NINT:
-            snprintf(buf, sizeof(buf), "%" PRId64, item->asNint()->value());
-            out.append(buf);
-            break;
-
-        case cppbor::BSTR: {
-            const cppbor::Bstr* bstr = item->asBstr();
-            const vector<uint8_t>& value = bstr->value();
-            if (value.size() > maxBStrSize) {
-                unsigned char digest[SHA_DIGEST_LENGTH];
-                SHA_CTX ctx;
-                SHA1_Init(&ctx);
-                SHA1_Update(&ctx, value.data(), value.size());
-                SHA1_Final(digest, &ctx);
-                char buf2[SHA_DIGEST_LENGTH * 2 + 1];
-                for (size_t n = 0; n < SHA_DIGEST_LENGTH; n++) {
-                    snprintf(buf2 + n * 2, 3, "%02x", digest[n]);
-                }
-                snprintf(buf, sizeof(buf), "<bstr size=%zd sha1=%s>", value.size(), buf2);
-                out.append(buf);
-            } else {
-                out.append("{");
-                for (size_t n = 0; n < value.size(); n++) {
-                    if (n > 0) {
-                        out.append(", ");
-                    }
-                    snprintf(buf, sizeof(buf), "0x%02x", value[n]);
-                    out.append(buf);
-                }
-                out.append("}");
-            }
-        } break;
-
-        case cppbor::TSTR:
-            out.append("'");
-            {
-                // TODO: escape "'" characters
-                out.append(item->asTstr()->value().c_str());
-            }
-            out.append("'");
-            break;
-
-        case cppbor::ARRAY: {
-            const cppbor::Array* array = item->asArray();
-            if (array->size() == 0) {
-                out.append("[]");
-            } else if (cborAreAllElementsNonCompound(array)) {
-                out.append("[");
-                for (size_t n = 0; n < array->size(); n++) {
-                    if (!cborPrettyPrintInternal((*array)[n].get(), out, indent + 2, maxBStrSize,
-                                                 mapKeysToNotPrint)) {
-                        return false;
-                    }
-                    out.append(", ");
-                }
-                out.append("]");
-            } else {
-                out.append("[\n" + indentString);
-                for (size_t n = 0; n < array->size(); n++) {
-                    out.append("  ");
-                    if (!cborPrettyPrintInternal((*array)[n].get(), out, indent + 2, maxBStrSize,
-                                                 mapKeysToNotPrint)) {
-                        return false;
-                    }
-                    out.append(",\n" + indentString);
-                }
-                out.append("]");
-            }
-        } break;
-
-        case cppbor::MAP: {
-            const cppbor::Map* map = item->asMap();
-
-            if (map->size() == 0) {
-                out.append("{}");
-            } else {
-                out.append("{\n" + indentString);
-                for (size_t n = 0; n < map->size(); n++) {
-                    out.append("  ");
-
-                    auto [map_key, map_value] = (*map)[n];
-
-                    if (!cborPrettyPrintInternal(map_key.get(), out, indent + 2, maxBStrSize,
-                                                 mapKeysToNotPrint)) {
-                        return false;
-                    }
-                    out.append(" : ");
-                    if (map_key->type() == cppbor::TSTR &&
-                        std::find(mapKeysToNotPrint.begin(), mapKeysToNotPrint.end(),
-                                  map_key->asTstr()->value()) != mapKeysToNotPrint.end()) {
-                        out.append("<not printed>");
-                    } else {
-                        if (!cborPrettyPrintInternal(map_value.get(), out, indent + 2, maxBStrSize,
-                                                     mapKeysToNotPrint)) {
-                            return false;
-                        }
-                    }
-                    out.append(",\n" + indentString);
-                }
-                out.append("}");
-            }
-        } break;
-
-        case cppbor::SEMANTIC: {
-            const cppbor::Semantic* semantic = item->asSemantic();
-            snprintf(buf, sizeof(buf), "tag %" PRIu64 " ", semantic->value());
-            out.append(buf);
-            cborPrettyPrintInternal(semantic->child().get(), out, indent, maxBStrSize,
-                                    mapKeysToNotPrint);
-        } break;
-
-        case cppbor::SIMPLE:
-            const cppbor::Bool* asBool = item->asSimple()->asBool();
-            const cppbor::Null* asNull = item->asSimple()->asNull();
-            if (asBool != nullptr) {
-                out.append(asBool->value() ? "true" : "false");
-            } else if (asNull != nullptr) {
-                out.append("null");
-            } else {
-                LOG(ERROR) << "Only boolean/null is implemented for SIMPLE";
-                return false;
-            }
-            break;
-    }
-
-    return true;
-}
-
-string cborPrettyPrint(const vector<uint8_t>& encodedCbor, size_t maxBStrSize,
-                       const vector<string>& mapKeysToNotPrint) {
-    auto [item, _, message] = cppbor::parse(encodedCbor);
-    if (item == nullptr) {
-        LOG(ERROR) << "Data to pretty print is not valid CBOR: " << message;
-        return "";
-    }
-
-    string out;
-    cborPrettyPrintInternal(item.get(), out, 0, maxBStrSize, mapKeysToNotPrint);
-    return out;
-}
-
-// ---------------------------------------------------------------------------
 // Crypto functionality / abstraction.
 // ---------------------------------------------------------------------------
 
@@ -2140,7 +1947,7 @@
     }
 
     for (size_t n = 0; n < protectedHeaders->size(); n++) {
-        auto [keyItem, valueItem] = (*protectedHeaders)[n];
+        auto& [keyItem, valueItem] = (*protectedHeaders)[n];
         const cppbor::Int* number = keyItem->asInt();
         if (number == nullptr) {
             LOG(ERROR) << "Key item in top-level map is not a number";
@@ -2183,7 +1990,7 @@
     }
 
     for (size_t n = 0; n < unprotectedHeaders->size(); n++) {
-        auto [keyItem, valueItem] = (*unprotectedHeaders)[n];
+        auto& [keyItem, valueItem] = (*unprotectedHeaders)[n];
         const cppbor::Int* number = keyItem->asInt();
         if (number == nullptr) {
             LOG(ERROR) << "Key item in top-level map is not a number";
@@ -2335,9 +2142,9 @@
                     .add("DeviceAuthentication")
                     .add(std::move(sessionTranscriptItem))
                     .add(docType)
-                    .add(cppbor::Semantic(kSemanticTagEncodedCbor, deviceNameSpacesEncoded));
+                    .add(cppbor::SemanticTag(kSemanticTagEncodedCbor, deviceNameSpacesEncoded));
     vector<uint8_t> deviceAuthenticationBytes =
-            cppbor::Semantic(kSemanticTagEncodedCbor, deviceAuthentication.encode()).encode();
+            cppbor::SemanticTag(kSemanticTagEncodedCbor, deviceAuthentication.encode()).encode();
     optional<vector<uint8_t>> calculatedMac =
             support::coseMac0(eMacKey, {},                 // payload
                               deviceAuthenticationBytes);  // detached content
diff --git a/identity/support/tests/IdentityCredentialSupportTest.cpp b/identity/support/tests/IdentityCredentialSupportTest.cpp
index 509133c..4c9b87a 100644
--- a/identity/support/tests/IdentityCredentialSupportTest.cpp
+++ b/identity/support/tests/IdentityCredentialSupportTest.cpp
@@ -55,99 +55,6 @@
     EXPECT_FALSE(support::decodeHex("012"));
 }
 
-TEST(IdentityCredentialSupport, CborPrettyPrint) {
-    EXPECT_EQ("'Some text'", support::cborPrettyPrint(cppbor::Tstr("Some text").encode()));
-
-    EXPECT_EQ("''", support::cborPrettyPrint(cppbor::Tstr("").encode()));
-
-    EXPECT_EQ("{0x01, 0x00, 0x02, 0xf0, 0xff, 0x40}",
-              support::cborPrettyPrint(
-                      cppbor::Bstr(vector<uint8_t>({1, 0, 2, 240, 255, 64})).encode()));
-
-    EXPECT_EQ("{}", support::cborPrettyPrint(cppbor::Bstr(vector<uint8_t>()).encode()));
-
-    EXPECT_EQ("true", support::cborPrettyPrint(cppbor::Bool(true).encode()));
-
-    EXPECT_EQ("false", support::cborPrettyPrint(cppbor::Bool(false).encode()));
-
-    EXPECT_EQ("42", support::cborPrettyPrint(cppbor::Uint(42).encode()));
-
-    EXPECT_EQ("9223372036854775807",  // 0x7fff ffff ffff ffff
-              support::cborPrettyPrint(cppbor::Uint(std::numeric_limits<int64_t>::max()).encode()));
-
-    EXPECT_EQ("-42", support::cborPrettyPrint(cppbor::Nint(-42).encode()));
-
-    EXPECT_EQ("-9223372036854775808",  // -0x8000 0000 0000 0000
-              support::cborPrettyPrint(cppbor::Nint(std::numeric_limits<int64_t>::min()).encode()));
-}
-
-TEST(IdentityCredentialSupport, CborPrettyPrintCompound) {
-    cppbor::Array array = cppbor::Array("foo", "bar", "baz");
-    EXPECT_EQ("['foo', 'bar', 'baz', ]", support::cborPrettyPrint(array.encode()));
-
-    cppbor::Map map = cppbor::Map().add("foo", 42).add("bar", 43).add("baz", 44);
-    EXPECT_EQ(
-            "{\n"
-            "  'foo' : 42,\n"
-            "  'bar' : 43,\n"
-            "  'baz' : 44,\n"
-            "}",
-            support::cborPrettyPrint(map.encode()));
-
-    cppbor::Array array2 = cppbor::Array(cppbor::Tstr("Some text"), cppbor::Nint(-42));
-    EXPECT_EQ("['Some text', -42, ]", support::cborPrettyPrint(array2.encode()));
-
-    cppbor::Map map2 = cppbor::Map().add(42, "foo").add(43, "bar").add(44, "baz");
-    EXPECT_EQ(
-            "{\n"
-            "  42 : 'foo',\n"
-            "  43 : 'bar',\n"
-            "  44 : 'baz',\n"
-            "}",
-            support::cborPrettyPrint(map2.encode()));
-
-    cppbor::Array deeplyNestedArrays =
-            cppbor::Array(cppbor::Array(cppbor::Array("a", "b", "c")),
-                          cppbor::Array(cppbor::Array("d", "e", cppbor::Array("f", "g"))));
-    EXPECT_EQ(
-            "[\n"
-            "  ['a', 'b', 'c', ],\n"
-            "  [\n    'd',\n"
-            "    'e',\n"
-            "    ['f', 'g', ],\n"
-            "  ],\n"
-            "]",
-            support::cborPrettyPrint(deeplyNestedArrays.encode()));
-
-    EXPECT_EQ(
-            "[\n"
-            "  {0x0a, 0x0b},\n"
-            "  'foo',\n"
-            "  42,\n"
-            "  ['foo', 'bar', 'baz', ],\n"
-            "  {\n"
-            "    'foo' : 42,\n"
-            "    'bar' : 43,\n"
-            "    'baz' : 44,\n"
-            "  },\n"
-            "  {\n"
-            "    'deep1' : ['Some text', -42, ],\n"
-            "    'deep2' : {\n"
-            "      42 : 'foo',\n"
-            "      43 : 'bar',\n"
-            "      44 : 'baz',\n"
-            "    },\n"
-            "  },\n"
-            "]",
-            support::cborPrettyPrint(cppbor::Array(cppbor::Bstr(vector<uint8_t>{10, 11}),
-                                                   cppbor::Tstr("foo"), cppbor::Uint(42),
-                                                   std::move(array), std::move(map),
-                                                   (cppbor::Map()
-                                                            .add("deep1", std::move(array2))
-                                                            .add("deep2", std::move(map2))))
-                                             .encode()));
-}
-
 TEST(IdentityCredentialSupport, Signatures) {
     vector<uint8_t> data = {1, 2, 3};
 
@@ -219,7 +126,7 @@
     ASSERT_EQ(data, payload.value());
 
     // Finally, check that |coseSign1| are the bytes of a valid COSE_Sign1 message
-    string out = support::cborPrettyPrint(coseSign1.value());
+    string out = cppbor::prettyPrint(coseSign1.value());
     out = replaceLine(out, -2, "  [] // Signature Removed");
     EXPECT_EQ(
             "[\n"
@@ -250,7 +157,7 @@
     ASSERT_EQ(0, payload.value().size());
 
     // Finally, check that |coseSign1| are the bytes of a valid COSE_Sign1 message
-    string out = support::cborPrettyPrint(coseSign1.value());
+    string out = cppbor::prettyPrint(coseSign1.value());
     out = replaceLine(out, -2, "  [] // Signature Removed");
     EXPECT_EQ(
             "[\n"
@@ -411,7 +318,7 @@
             "0x86, 0x5c, 0x28, 0x2c, 0xd5, 0xa5, 0x13, 0xff, 0x3b, 0xd1, 0xde, 0x70, 0x5e, 0xbb, "
             "0xe2, 0x2d, 0x42, 0xbe, 0x53},\n"
             "]",
-            support::cborPrettyPrint(mac.value()));
+            cppbor::prettyPrint(mac.value()));
 }
 
 TEST(IdentityCredentialSupport, CoseMac0DetachedContent) {
@@ -433,7 +340,7 @@
             "0x86, 0x5c, 0x28, 0x2c, 0xd5, 0xa5, 0x13, 0xff, 0x3b, 0xd1, 0xde, 0x70, 0x5e, 0xbb, "
             "0xe2, 0x2d, 0x42, 0xbe, 0x53},\n"
             "]",
-            support::cborPrettyPrint(mac.value()));
+            cppbor::prettyPrint(mac.value()));
 }
 
 // Generates a private key in DER format for a small value of 'd'.
@@ -460,8 +367,8 @@
 
 const cppbor::Item* findValueForTstr(const cppbor::Map* map, const string& keyValue) {
     // TODO: Need cast until libcppbor's Map::get() is marked as const
-    auto [item, found] = ((cppbor::Map*)map)->get(keyValue);
-    if (!found) {
+    const auto& item = map->get(keyValue);
+    if (!item) {
         return nullptr;
     }
     return item.get();
@@ -483,12 +390,13 @@
     return item->asMap();
 }
 
-const cppbor::Semantic* findSemanticValueForTstr(const cppbor::Map* map, const string& keyValue) {
+const cppbor::SemanticTag* findSemanticValueForTstr(const cppbor::Map* map,
+                                                    const string& keyValue) {
     const cppbor::Item* item = findValueForTstr(map, keyValue);
     if (item == nullptr) {
         return nullptr;
     }
-    return item->asSemantic();
+    return item->asSemanticTag();
 }
 
 const std::string findStringValueForTstr(const cppbor::Map* map, const string& keyValue) {
@@ -576,11 +484,11 @@
     auto [sessionEstablishmentItem, _se, _se2] = cppbor::parse(sessionEstablishmentEncoded.value());
     const cppbor::Map* sessionEstablishment = sessionEstablishmentItem->asMap();
     ASSERT_NE(sessionEstablishment, nullptr);
-    const cppbor::Semantic* eReaderKeyBytes =
+    const cppbor::SemanticTag* eReaderKeyBytes =
             findSemanticValueForTstr(sessionEstablishment, "eReaderKeyBytes");
     ASSERT_NE(eReaderKeyBytes, nullptr);
-    ASSERT_EQ(eReaderKeyBytes->value(), 24);
-    const cppbor::Bstr* eReaderKeyBstr = eReaderKeyBytes->child()->asBstr();
+    ASSERT_EQ(eReaderKeyBytes->semanticTag(), 24);
+    const cppbor::Bstr* eReaderKeyBstr = eReaderKeyBytes->asBstr();
     ASSERT_NE(eReaderKeyBstr, nullptr);
     vector<uint8_t> eReaderKeyEncoded = eReaderKeyBstr->value();
     // TODO: verify this agrees with ephemeralReaderKeyX and ephemeralReaderKeyY
@@ -605,12 +513,12 @@
     //   SessionTranscriptBytes = #6.24(bstr .cbor SessionTranscript)
     //
     cppbor::Array sessionTranscript;
-    sessionTranscript.add(cppbor::Semantic(24, deviceEngagementEncoded));
-    sessionTranscript.add(cppbor::Semantic(24, eReaderKeyEncoded));
+    sessionTranscript.add(cppbor::SemanticTag(24, deviceEngagementEncoded));
+    sessionTranscript.add(cppbor::SemanticTag(24, eReaderKeyEncoded));
     sessionTranscript.add(cppbor::Null());
     vector<uint8_t> sessionTranscriptEncoded = sessionTranscript.encode();
     vector<uint8_t> sessionTranscriptBytes =
-            cppbor::Semantic(24, sessionTranscriptEncoded).encode();
+            cppbor::SemanticTag(24, sessionTranscriptEncoded).encode();
 
     // The expected EMacKey is 4c1ebb8aacc633465390fa44edfdb49cb57f2e079aaa771d812584699c0b97e2
     //
@@ -696,11 +604,11 @@
 
     // Dig out the encoded form of DeviceNameSpaces
     //
-    const cppbor::Semantic* deviceNameSpacesBytes =
+    const cppbor::SemanticTag* deviceNameSpacesBytes =
             findSemanticValueForTstr(deviceSigned, "nameSpaces");
     ASSERT_NE(deviceNameSpacesBytes, nullptr);
-    ASSERT_EQ(deviceNameSpacesBytes->value(), 24);
-    const cppbor::Bstr* deviceNameSpacesBstr = deviceNameSpacesBytes->child()->asBstr();
+    ASSERT_EQ(deviceNameSpacesBytes->semanticTag(), 24);
+    const cppbor::Bstr* deviceNameSpacesBstr = deviceNameSpacesBytes->asBstr();
     ASSERT_NE(deviceNameSpacesBstr, nullptr);
     vector<uint8_t> deviceNameSpacesEncoded = deviceNameSpacesBstr->value();
 
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
index 8d6e74a..ea40971 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
@@ -117,6 +117,9 @@
 DECLARE_TYPED_TAG(ATTESTATION_ID_PRODUCT);
 DECLARE_TYPED_TAG(ATTESTATION_ID_MANUFACTURER);
 DECLARE_TYPED_TAG(ATTESTATION_ID_MODEL);
+DECLARE_TYPED_TAG(ATTESTATION_ID_SERIAL);
+DECLARE_TYPED_TAG(ATTESTATION_ID_IMEI);
+DECLARE_TYPED_TAG(ATTESTATION_ID_MEID);
 DECLARE_TYPED_TAG(AUTH_TIMEOUT);
 DECLARE_TYPED_TAG(BLOB_USAGE_REQUIREMENTS);
 DECLARE_TYPED_TAG(BLOCK_MODE);
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/light/2.0/default/Light.cpp b/light/2.0/default/Light.cpp
index 5484d2d..3febf6b 100644
--- a/light/2.0/default/Light.cpp
+++ b/light/2.0/default/Light.cpp
@@ -140,7 +140,7 @@
         ret = hwModule->methods->open(hwModule, name,
             reinterpret_cast<hw_device_t**>(&lightDevice));
         if (ret != 0) {
-            ALOGE("light_open %s %s failed: %d", LIGHTS_HARDWARE_MODULE_ID, name, ret);
+            ALOGI("light_open %s %s failed: %d", LIGHTS_HARDWARE_MODULE_ID, name, ret);
         }
     } else {
         ALOGE("hw_get_module %s %s failed: %d", LIGHTS_HARDWARE_MODULE_ID, name, ret);
diff --git a/media/c2/1.2/Android.bp b/media/c2/1.2/Android.bp
new file mode 100644
index 0000000..6d3e74d
--- /dev/null
+++ b/media/c2/1.2/Android.bp
@@ -0,0 +1,40 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+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"],
+}
+
+hidl_interface {
+    name: "android.hardware.media.c2@1.2",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "IComponent.hal",
+        "IComponentStore.hal",
+    ],
+    interfaces: [
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.bufferqueue@2.0",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+        "android.hardware.media.bufferpool@2.0",
+        "android.hardware.media.c2@1.0",
+        "android.hardware.media.c2@1.1",
+        "android.hardware.media.omx@1.0",
+        "android.hardware.media@1.0",
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: false,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media.swcodec",
+        "test_com.android.media.swcodec",
+    ],
+}
diff --git a/media/c2/1.2/IComponent.hal b/media/c2/1.2/IComponent.hal
new file mode 100644
index 0000000..088d810
--- /dev/null
+++ b/media/c2/1.2/IComponent.hal
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+package android.hardware.media.c2@1.2;
+
+import android.hardware.graphics.bufferqueue@2.0::IGraphicBufferProducer;
+import android.hardware.media.c2@1.1::IComponent;
+import android.hardware.media.c2@1.0::Status;
+
+
+/**
+ * Interface for a Codec2 component corresponding to API level 1.2 or below.
+ * Components have two states: stopped and running. The running state has three
+ * sub-states: executing, tripped and error.
+ *
+ * All methods in `IComponent` must not block. If a method call cannot be
+ * completed in a timely manner, it must return `TIMED_OUT` in the return
+ * status.
+ *
+ * @note This is an extension of version 1.1 of `IComponent`. The purpose of the
+ * extension is to add blocking allocation of output buffer from surface.
+ */
+interface IComponent extends @1.1::IComponent {
+    /**
+     * Starts using a surface for output with a synchronization object
+     *
+     * This method must not block.
+     *
+     * @param blockPoolId Id of the `C2BlockPool` to be associated with the
+     *     output surface.
+     * @param surface Output surface.
+     * @param syncObject synchronization object for buffer allocation between
+     *     Framework and Component.
+     * @return status Status of the call, which may be
+     *   - `OK`        - The operation completed successfully.
+     *   - `CANNOT_DO` - The component does not support an output surface.
+     *   - `REFUSED`   - The output surface cannot be accessed.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     */
+    setOutputSurfaceWithSyncObj(
+            uint64_t blockPoolId,
+            @2.0::IGraphicBufferProducer surface,
+            SurfaceSyncObj syncObject
+        ) generates (
+            Status status
+        );
+};
diff --git a/media/c2/1.2/IComponentStore.hal b/media/c2/1.2/IComponentStore.hal
new file mode 100644
index 0000000..c38fc7a
--- /dev/null
+++ b/media/c2/1.2/IComponentStore.hal
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+package android.hardware.media.c2@1.2;
+
+import android.hardware.media.bufferpool@2.0::IClientManager;
+import android.hardware.media.c2@1.0::IComponentListener;
+import android.hardware.media.c2@1.1::IComponentStore;
+import android.hardware.media.c2@1.0::Status;
+
+import IComponent;
+
+/**
+ * Entry point for Codec2 HAL.
+ *
+ * All methods in `IComponentStore` must not block. If a method call cannot be
+ * completed in a timely manner, it must return `TIMED_OUT` in the return
+ * status. The only exceptions are getPoolClientManager() and getConfigurable(),
+ * which must always return immediately.
+ *
+ * @note This is an extension of version 1.1 of `IComponentStore`. The purpose
+ * of the extension is to add support for blocking output buffer allocator.
+ */
+interface IComponentStore extends @1.1::IComponentStore {
+    /**
+     * Creates a component by name.
+     *
+     * @param name Name of the component to create. This must match one of the
+     *     names returned by listComponents().
+     * @param listener Callback receiver.
+     * @param pool `IClientManager` object of the BufferPool in the client
+     *     process. This may be null if the client does not own a BufferPool.
+     * @return status Status of the call, which may be
+     *   - `OK`        - The component was created successfully.
+     *   - `NOT_FOUND` - There is no component with the given name.
+     *   - `NO_MEMORY` - Not enough memory to create the component.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return comp The created component if @p status is `OK`.
+     *
+     * @sa IComponentListener.
+     */
+    createComponent_1_2(
+            string name,
+            IComponentListener listener,
+            IClientManager pool
+        ) generates (
+            Status status,
+            IComponent comp
+        );
+};
diff --git a/media/c2/1.2/types.hal b/media/c2/1.2/types.hal
new file mode 100644
index 0000000..096edbd
--- /dev/null
+++ b/media/c2/1.2/types.hal
@@ -0,0 +1,52 @@
+/*
+ * 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.media.c2@1.2;
+
+/**
+ * Surface(BufferQueue/IGBP) synchronization object regarding # of dequeued
+ * output buffers. This keeps # of dequeued buffers from Surface less than
+ * configured max # of dequeued buffers all the time.
+ */
+struct SurfaceSyncObj {
+    /**
+     * ASharedMemory for synchronization data. Layout is below
+     *
+     * |lock(futex)                               4bytes|
+     * |conditional_variable(futex)               4bytes|
+     * |# of max dequeable buffer                 4bytes|
+     * |# of dequeued buffer                      4bytes|
+     * |Status of the surface                     4bytes|
+     *      INIT        = 0, Configuring surface is not finished.
+     *      ACTIVE      = 1, Surface is ready to allocate(dequeue).
+     *      SWITCHING   = 2, Switching to the new surface. It is blocked
+     *                       to allocate(dequeue) a buffer until switching
+     *                       completes.
+     */
+    handle syncMemory;
+
+    // Read-only.
+    // The values which are tied and not changed with respect to Surface
+    // which is currently set up.
+    /** BufferQueue id. */
+    uint64_t bqId;
+    /** Generation id. */
+    uint32_t generationId;
+    /** Consumer usage flags. See +ndk
+      * libnativewindow#AHardwareBuffer_UsageFlags for possible values.
+      */
+    uint64_t consumerUsage;
+};
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h
index 8329303..7849ca7 100644
--- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h
@@ -44,7 +44,9 @@
     OptionalCacheHold cacheMemory(const nn::SharedMemory& memory) const override;
 
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
-            const nn::Request& request, nn::MeasureTiming measure) const override;
+            const nn::Request& request, nn::MeasureTiming measure,
+            const nn::OptionalTimePoint& deadline,
+            const nn::OptionalDuration& loopTimeoutDuration) const override;
 
   private:
     const nn::SharedPreparedModel kPreparedModel;
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h
index b695f48..1baabdf 100644
--- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h
@@ -22,10 +22,15 @@
 #include <android-base/logging.h>
 #include <android/hardware/neuralnetworks/1.0/types.h>
 #include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
 #include <nnapi/Types.h>
+#include <nnapi/Validation.h>
+#include <nnapi/hal/HandleError.h>
 
 namespace android::hardware::neuralnetworks::V1_0::utils {
 
+constexpr auto kVersion = nn::Version::ANDROID_OC_MR1;
+
 template <typename Type>
 nn::Result<void> validate(const Type& halObject) {
     const auto maybeCanonical = nn::convert(halObject);
@@ -45,6 +50,15 @@
 }
 
 template <typename Type>
+nn::GeneralResult<void> compliantVersion(const Type& canonical) {
+    const auto version = NN_TRY(hal::utils::makeGeneralFailure(nn::validate(canonical)));
+    if (version > kVersion) {
+        return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
+    }
+    return {};
+}
+
+template <typename Type>
 auto convertFromNonCanonical(const Type& nonCanonicalObject)
         -> decltype(convert(nn::convert(nonCanonicalObject).value())) {
     return convert(NN_TRY(nn::convert(nonCanonicalObject)));
diff --git a/neuralnetworks/1.0/utils/src/Burst.cpp b/neuralnetworks/1.0/utils/src/Burst.cpp
index 971ad08..e3a9757 100644
--- a/neuralnetworks/1.0/utils/src/Burst.cpp
+++ b/neuralnetworks/1.0/utils/src/Burst.cpp
@@ -20,6 +20,7 @@
 #include <nnapi/IBurst.h>
 #include <nnapi/IPreparedModel.h>
 #include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
 #include <nnapi/Types.h>
 
 #include <memory>
@@ -48,8 +49,10 @@
 }
 
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Burst::execute(
-        const nn::Request& request, nn::MeasureTiming measure) const {
-    return kPreparedModel->execute(request, measure, {}, {});
+        const nn::Request& request, nn::MeasureTiming measure,
+        const nn::OptionalTimePoint& deadline,
+        const nn::OptionalDuration& loopTimeoutDuration) const {
+    return kPreparedModel->execute(request, measure, deadline, loopTimeoutDuration);
 }
 
 }  // namespace android::hardware::neuralnetworks::V1_0::utils
diff --git a/neuralnetworks/1.0/utils/src/Conversions.cpp b/neuralnetworks/1.0/utils/src/Conversions.cpp
index 700b050..c0498eb 100644
--- a/neuralnetworks/1.0/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.0/utils/src/Conversions.cpp
@@ -35,6 +35,8 @@
 #include <utility>
 #include <variant>
 
+#include "Utils.h"
+
 namespace {
 
 template <typename Type>
@@ -42,8 +44,6 @@
     return static_cast<std::underlying_type_t<Type>>(value);
 }
 
-constexpr auto kVersion = android::nn::Version::ANDROID_OC_MR1;
-
 }  // namespace
 
 namespace android::nn {
@@ -53,13 +53,13 @@
 using hardware::hidl_vec;
 
 template <typename Input>
-using unvalidatedConvertOutput =
+using UnvalidatedConvertOutput =
         std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
 
 template <typename Type>
-GeneralResult<std::vector<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
+GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> unvalidatedConvert(
         const hidl_vec<Type>& arguments) {
-    std::vector<unvalidatedConvertOutput<Type>> canonical;
+    std::vector<UnvalidatedConvertOutput<Type>> canonical;
     canonical.reserve(arguments.size());
     for (const auto& argument : arguments) {
         canonical.push_back(NN_TRY(nn::unvalidatedConvert(argument)));
@@ -68,16 +68,9 @@
 }
 
 template <typename Type>
-decltype(nn::unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& halObject) {
+GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& halObject) {
     auto canonical = NN_TRY(nn::unvalidatedConvert(halObject));
-    const auto maybeVersion = validate(canonical);
-    if (!maybeVersion.has_value()) {
-        return error() << maybeVersion.error();
-    }
-    const auto version = maybeVersion.value();
-    if (version > kVersion) {
-        return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
-    }
+    NN_TRY(hal::V1_0::utils::compliantVersion(canonical));
     return canonical;
 }
 
@@ -248,13 +241,13 @@
 namespace {
 
 template <typename Input>
-using unvalidatedConvertOutput =
+using UnvalidatedConvertOutput =
         std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
 
 template <typename Type>
-nn::GeneralResult<hidl_vec<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
+nn::GeneralResult<hidl_vec<UnvalidatedConvertOutput<Type>>> unvalidatedConvert(
         const std::vector<Type>& arguments) {
-    hidl_vec<unvalidatedConvertOutput<Type>> halObject(arguments.size());
+    hidl_vec<UnvalidatedConvertOutput<Type>> halObject(arguments.size());
     for (size_t i = 0; i < arguments.size(); ++i) {
         halObject[i] = NN_TRY(utils::unvalidatedConvert(arguments[i]));
     }
@@ -262,15 +255,8 @@
 }
 
 template <typename Type>
-decltype(utils::unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& canonical) {
-    const auto maybeVersion = nn::validate(canonical);
-    if (!maybeVersion.has_value()) {
-        return nn::error() << maybeVersion.error();
-    }
-    const auto version = maybeVersion.value();
-    if (version > kVersion) {
-        return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
-    }
+nn::GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& canonical) {
+    NN_TRY(compliantVersion(canonical));
     return utils::unvalidatedConvert(canonical);
 }
 
diff --git a/neuralnetworks/1.0/utils/test/MockDevice.h b/neuralnetworks/1.0/utils/test/MockDevice.h
index 0fb59e3..7c399ec 100644
--- a/neuralnetworks/1.0/utils/test/MockDevice.h
+++ b/neuralnetworks/1.0/utils/test/MockDevice.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_DEVICE
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_DEVICE
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_DEVICE_H
 
 #include <android/hardware/neuralnetworks/1.0/IDevice.h>
 #include <gmock/gmock.h>
@@ -83,4 +83,4 @@
 
 }  // namespace android::hardware::neuralnetworks::V1_0::utils
 
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_DEVICE
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_DEVICE_H
diff --git a/neuralnetworks/1.0/utils/test/MockPreparedModel.h b/neuralnetworks/1.0/utils/test/MockPreparedModel.h
index 7a48a83..03f1a4b 100644
--- a/neuralnetworks/1.0/utils/test/MockPreparedModel.h
+++ b/neuralnetworks/1.0/utils/test/MockPreparedModel.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_PREPARED_MODEL
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_PREPARED_MODEL
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_PREPARED_MODEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_PREPARED_MODEL_H
 
 #include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
 #include <gmock/gmock.h>
@@ -82,4 +82,4 @@
 
 }  // namespace android::hardware::neuralnetworks::V1_0::utils
 
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_PREPARED_MODEL
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_TEST_MOCK_PREPARED_MODEL_H
diff --git a/neuralnetworks/1.0/utils/test/PreparedModelTest.cpp b/neuralnetworks/1.0/utils/test/PreparedModelTest.cpp
index a5cbc72..f19ed77 100644
--- a/neuralnetworks/1.0/utils/test/PreparedModelTest.cpp
+++ b/neuralnetworks/1.0/utils/test/PreparedModelTest.cpp
@@ -224,7 +224,19 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-// TODO: test burst execution if/when it is added to nn::IPreparedModel.
+TEST(PreparedModelTest, configureExecutionBurst) {
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+
+    // run test
+    const auto result = preparedModel->configureExecutionBurst();
+
+    // verify result
+    ASSERT_TRUE(result.has_value())
+            << "Failed with " << result.error().code << ": " << result.error().message;
+    EXPECT_NE(result.value(), nullptr);
+}
 
 TEST(PreparedModelTest, getUnderlyingResource) {
     // setup test
diff --git a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h
index 09597a3..a8cf8cf 100644
--- a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h
+++ b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h
@@ -22,12 +22,16 @@
 #include <android-base/logging.h>
 #include <android/hardware/neuralnetworks/1.1/types.h>
 #include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
 #include <nnapi/Types.h>
+#include <nnapi/Validation.h>
 #include <nnapi/hal/1.0/Conversions.h>
+#include <nnapi/hal/HandleError.h>
 
 namespace android::hardware::neuralnetworks::V1_1::utils {
 
 constexpr auto kDefaultExecutionPreference = ExecutionPreference::FAST_SINGLE_ANSWER;
+constexpr auto kVersion = nn::Version::ANDROID_P;
 
 template <typename Type>
 nn::Result<void> validate(const Type& halObject) {
@@ -48,6 +52,15 @@
 }
 
 template <typename Type>
+nn::GeneralResult<void> compliantVersion(const Type& canonical) {
+    const auto version = NN_TRY(hal::utils::makeGeneralFailure(nn::validate(canonical)));
+    if (version > kVersion) {
+        return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
+    }
+    return {};
+}
+
+template <typename Type>
 auto convertFromNonCanonical(const Type& nonCanonicalObject)
         -> decltype(convert(nn::convert(nonCanonicalObject).value())) {
     return convert(NN_TRY(nn::convert(nonCanonicalObject)));
diff --git a/neuralnetworks/1.1/utils/src/Conversions.cpp b/neuralnetworks/1.1/utils/src/Conversions.cpp
index d07f7d0..467ceb3 100644
--- a/neuralnetworks/1.1/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.1/utils/src/Conversions.cpp
@@ -35,11 +35,7 @@
 #include <type_traits>
 #include <utility>
 
-namespace {
-
-constexpr auto kVersion = android::nn::Version::ANDROID_P;
-
-}  // namespace
+#include "Utils.h"
 
 namespace android::nn {
 namespace {
@@ -47,13 +43,13 @@
 using hardware::hidl_vec;
 
 template <typename Input>
-using unvalidatedConvertOutput =
+using UnvalidatedConvertOutput =
         std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
 
 template <typename Type>
-GeneralResult<std::vector<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
+GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> unvalidatedConvert(
         const hidl_vec<Type>& arguments) {
-    std::vector<unvalidatedConvertOutput<Type>> canonical;
+    std::vector<UnvalidatedConvertOutput<Type>> canonical;
     canonical.reserve(arguments.size());
     for (const auto& argument : arguments) {
         canonical.push_back(NN_TRY(nn::unvalidatedConvert(argument)));
@@ -62,16 +58,9 @@
 }
 
 template <typename Type>
-decltype(nn::unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& halObject) {
+GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& halObject) {
     auto canonical = NN_TRY(nn::unvalidatedConvert(halObject));
-    const auto maybeVersion = validate(canonical);
-    if (!maybeVersion.has_value()) {
-        return error() << maybeVersion.error();
-    }
-    const auto version = maybeVersion.value();
-    if (version > kVersion) {
-        return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
-    }
+    NN_TRY(hal::V1_1::utils::compliantVersion(canonical));
     return canonical;
 }
 
@@ -180,13 +169,13 @@
 }
 
 template <typename Input>
-using unvalidatedConvertOutput =
+using UnvalidatedConvertOutput =
         std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
 
 template <typename Type>
-nn::GeneralResult<hidl_vec<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
+nn::GeneralResult<hidl_vec<UnvalidatedConvertOutput<Type>>> unvalidatedConvert(
         const std::vector<Type>& arguments) {
-    hidl_vec<unvalidatedConvertOutput<Type>> halObject(arguments.size());
+    hidl_vec<UnvalidatedConvertOutput<Type>> halObject(arguments.size());
     for (size_t i = 0; i < arguments.size(); ++i) {
         halObject[i] = NN_TRY(unvalidatedConvert(arguments[i]));
     }
@@ -194,16 +183,9 @@
 }
 
 template <typename Type>
-decltype(utils::unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& canonical) {
-    const auto maybeVersion = nn::validate(canonical);
-    if (!maybeVersion.has_value()) {
-        return nn::error() << maybeVersion.error();
-    }
-    const auto version = maybeVersion.value();
-    if (version > kVersion) {
-        return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
-    }
-    return utils::unvalidatedConvert(canonical);
+nn::GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& canonical) {
+    NN_TRY(compliantVersion(canonical));
+    return unvalidatedConvert(canonical);
 }
 
 }  // anonymous namespace
diff --git a/neuralnetworks/1.1/utils/test/MockDevice.h b/neuralnetworks/1.1/utils/test/MockDevice.h
index 3b92e58..db7392d 100644
--- a/neuralnetworks/1.1/utils/test/MockDevice.h
+++ b/neuralnetworks/1.1/utils/test/MockDevice.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_TEST_MOCK_DEVICE
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_TEST_MOCK_DEVICE
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_TEST_MOCK_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_TEST_MOCK_DEVICE_H
 
 #include <android/hardware/neuralnetworks/1.1/IDevice.h>
 #include <gmock/gmock.h>
@@ -92,4 +92,4 @@
 
 }  // namespace android::hardware::neuralnetworks::V1_1::utils
 
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_TEST_MOCK_DEVICE
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_TEST_MOCK_DEVICE_H
diff --git a/neuralnetworks/1.1/utils/test/MockPreparedModel.h b/neuralnetworks/1.1/utils/test/MockPreparedModel.h
index aba731e..257397d 100644
--- a/neuralnetworks/1.1/utils/test/MockPreparedModel.h
+++ b/neuralnetworks/1.1/utils/test/MockPreparedModel.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_TEST_MOCK_PREPARED_MODEL
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_TEST_MOCK_PREPARED_MODEL
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_TEST_MOCK_PREPARED_MODEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_TEST_MOCK_PREPARED_MODEL_H
 
 #include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
 #include <gmock/gmock.h>
@@ -41,4 +41,4 @@
 
 }  // namespace android::hardware::neuralnetworks::V1_0::utils
 
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_TEST_MOCK_PREPARED_MODEL
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_TEST_MOCK_PREPARED_MODEL_H
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/ExecutionBurstController.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/ExecutionBurstController.h
index 6b6fc71..9669d8c0 100644
--- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/ExecutionBurstController.h
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/ExecutionBurstController.h
@@ -57,7 +57,8 @@
   public:
     using FallbackFunction =
             std::function<nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>(
-                    const nn::Request&, nn::MeasureTiming)>;
+                    const nn::Request&, nn::MeasureTiming, const nn::OptionalTimePoint&,
+                    const nn::OptionalDuration&)>;
 
     /**
      * NN runtime memory cache.
@@ -168,7 +169,9 @@
 
     // See IBurst::execute for information on this method.
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
-            const nn::Request& request, nn::MeasureTiming measure) const override;
+            const nn::Request& request, nn::MeasureTiming measure,
+            const nn::OptionalTimePoint& deadline,
+            const nn::OptionalDuration& loopTimeoutDuration) const override;
 
   private:
     mutable std::atomic_flag mExecutionInFlight = ATOMIC_FLAG_INIT;
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h
index 3233114..09691b6 100644
--- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h
@@ -22,19 +22,25 @@
 #include <android-base/logging.h>
 #include <android/hardware/neuralnetworks/1.2/types.h>
 #include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
 #include <nnapi/Types.h>
+#include <nnapi/Validation.h>
 #include <nnapi/hal/1.0/Conversions.h>
 #include <nnapi/hal/1.1/Conversions.h>
+#include <nnapi/hal/1.1/Utils.h>
+#include <nnapi/hal/HandleError.h>
 
 #include <limits>
 
 namespace android::hardware::neuralnetworks::V1_2::utils {
 
 using CacheToken = hidl_array<uint8_t, static_cast<size_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
+using V1_1::utils::kDefaultExecutionPreference;
 
 constexpr auto kDefaultMesaureTiming = MeasureTiming::NO;
 constexpr auto kNoTiming = Timing{.timeOnDevice = std::numeric_limits<uint64_t>::max(),
                                   .timeInDriver = std::numeric_limits<uint64_t>::max()};
+constexpr auto kVersion = nn::Version::ANDROID_Q;
 
 template <typename Type>
 nn::Result<void> validate(const Type& halObject) {
@@ -55,6 +61,15 @@
 }
 
 template <typename Type>
+nn::GeneralResult<void> compliantVersion(const Type& canonical) {
+    const auto version = NN_TRY(hal::utils::makeGeneralFailure(nn::validate(canonical)));
+    if (version > kVersion) {
+        return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
+    }
+    return {};
+}
+
+template <typename Type>
 auto convertFromNonCanonical(const Type& nonCanonicalObject)
         -> decltype(convert(nn::convert(nonCanonicalObject).value())) {
     return convert(NN_TRY(nn::convert(nonCanonicalObject)));
diff --git a/neuralnetworks/1.2/utils/src/Conversions.cpp b/neuralnetworks/1.2/utils/src/Conversions.cpp
index 2c45583..29945b7 100644
--- a/neuralnetworks/1.2/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.2/utils/src/Conversions.cpp
@@ -37,6 +37,8 @@
 #include <type_traits>
 #include <utility>
 
+#include "Utils.h"
+
 namespace {
 
 template <typename Type>
@@ -45,50 +47,23 @@
 }
 
 using HalDuration = std::chrono::duration<uint64_t, std::micro>;
-constexpr auto kVersion = android::nn::Version::ANDROID_Q;
-constexpr uint64_t kNoTiming = std::numeric_limits<uint64_t>::max();
 
 }  // namespace
 
 namespace android::nn {
 namespace {
 
-constexpr bool validOperandType(OperandType operandType) {
-    switch (operandType) {
-        case OperandType::FLOAT32:
-        case OperandType::INT32:
-        case OperandType::UINT32:
-        case OperandType::TENSOR_FLOAT32:
-        case OperandType::TENSOR_INT32:
-        case OperandType::TENSOR_QUANT8_ASYMM:
-        case OperandType::BOOL:
-        case OperandType::TENSOR_QUANT16_SYMM:
-        case OperandType::TENSOR_FLOAT16:
-        case OperandType::TENSOR_BOOL8:
-        case OperandType::FLOAT16:
-        case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
-        case OperandType::TENSOR_QUANT16_ASYMM:
-        case OperandType::TENSOR_QUANT8_SYMM:
-        case OperandType::OEM:
-        case OperandType::TENSOR_OEM_BYTE:
-            return true;
-        default:
-            break;
-    }
-    return isExtension(operandType);
-}
-
 using hardware::hidl_handle;
 using hardware::hidl_vec;
 
 template <typename Input>
-using unvalidatedConvertOutput =
+using UnvalidatedConvertOutput =
         std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
 
 template <typename Type>
-GeneralResult<std::vector<unvalidatedConvertOutput<Type>>> unvalidatedConvertVec(
+GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> unvalidatedConvert(
         const hidl_vec<Type>& arguments) {
-    std::vector<unvalidatedConvertOutput<Type>> canonical;
+    std::vector<UnvalidatedConvertOutput<Type>> canonical;
     canonical.reserve(arguments.size());
     for (const auto& argument : arguments) {
         canonical.push_back(NN_TRY(nn::unvalidatedConvert(argument)));
@@ -97,29 +72,16 @@
 }
 
 template <typename Type>
-GeneralResult<std::vector<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
-        const hidl_vec<Type>& arguments) {
-    return unvalidatedConvertVec(arguments);
-}
-
-template <typename Type>
-decltype(nn::unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& halObject) {
+GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& halObject) {
     auto canonical = NN_TRY(nn::unvalidatedConvert(halObject));
-    const auto maybeVersion = validate(canonical);
-    if (!maybeVersion.has_value()) {
-        return error() << maybeVersion.error();
-    }
-    const auto version = maybeVersion.value();
-    if (version > kVersion) {
-        return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
-    }
+    NN_TRY(hal::V1_2::utils::compliantVersion(canonical));
     return canonical;
 }
 
 template <typename Type>
-GeneralResult<std::vector<unvalidatedConvertOutput<Type>>> validatedConvert(
+GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> validatedConvert(
         const hidl_vec<Type>& arguments) {
-    std::vector<unvalidatedConvertOutput<Type>> canonical;
+    std::vector<UnvalidatedConvertOutput<Type>> canonical;
     canonical.reserve(arguments.size());
     for (const auto& argument : arguments) {
         canonical.push_back(NN_TRY(validatedConvert(argument)));
@@ -145,8 +107,7 @@
     const bool validOperandTypes = std::all_of(
             capabilities.operandPerformance.begin(), capabilities.operandPerformance.end(),
             [](const hal::V1_2::Capabilities::OperandPerformance& operandPerformance) {
-                const auto maybeType = unvalidatedConvert(operandPerformance.type);
-                return !maybeType.has_value() ? false : validOperandType(maybeType.value());
+                return validatedConvert(operandPerformance.type).has_value();
             });
     if (!validOperandTypes) {
         return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
@@ -275,6 +236,7 @@
 GeneralResult<Timing> unvalidatedConvert(const hal::V1_2::Timing& timing) {
     constexpr uint64_t kMaxTiming = std::chrono::floor<HalDuration>(Duration::max()).count();
     constexpr auto convertTiming = [](uint64_t halTiming) -> OptionalDuration {
+        constexpr uint64_t kNoTiming = std::numeric_limits<uint64_t>::max();
         if (halTiming == kNoTiming) {
             return {};
         }
@@ -378,25 +340,19 @@
 }
 
 template <typename Input>
-using unvalidatedConvertOutput =
+using UnvalidatedConvertOutput =
         std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
 
 template <typename Type>
-nn::GeneralResult<hidl_vec<unvalidatedConvertOutput<Type>>> unvalidatedConvertVec(
+nn::GeneralResult<hidl_vec<UnvalidatedConvertOutput<Type>>> unvalidatedConvert(
         const std::vector<Type>& arguments) {
-    hidl_vec<unvalidatedConvertOutput<Type>> halObject(arguments.size());
+    hidl_vec<UnvalidatedConvertOutput<Type>> halObject(arguments.size());
     for (size_t i = 0; i < arguments.size(); ++i) {
         halObject[i] = NN_TRY(unvalidatedConvert(arguments[i]));
     }
     return halObject;
 }
 
-template <typename Type>
-nn::GeneralResult<hidl_vec<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
-        const std::vector<Type>& arguments) {
-    return unvalidatedConvertVec(arguments);
-}
-
 nn::GeneralResult<Operand::ExtraParams> makeExtraParams(nn::Operand::NoParams /*noParams*/) {
     return Operand::ExtraParams{};
 }
@@ -416,22 +372,15 @@
 }
 
 template <typename Type>
-decltype(utils::unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& canonical) {
-    const auto maybeVersion = nn::validate(canonical);
-    if (!maybeVersion.has_value()) {
-        return nn::error() << maybeVersion.error();
-    }
-    const auto version = maybeVersion.value();
-    if (version > kVersion) {
-        return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
-    }
-    return utils::unvalidatedConvert(canonical);
+nn::GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& canonical) {
+    NN_TRY(compliantVersion(canonical));
+    return unvalidatedConvert(canonical);
 }
 
 template <typename Type>
-nn::GeneralResult<hidl_vec<unvalidatedConvertOutput<Type>>> validatedConvert(
+nn::GeneralResult<hidl_vec<UnvalidatedConvertOutput<Type>>> validatedConvert(
         const std::vector<Type>& arguments) {
-    hidl_vec<unvalidatedConvertOutput<Type>> halObject(arguments.size());
+    hidl_vec<UnvalidatedConvertOutput<Type>> halObject(arguments.size());
     for (size_t i = 0; i < arguments.size(); ++i) {
         halObject[i] = NN_TRY(validatedConvert(arguments[i]));
     }
@@ -469,7 +418,7 @@
                  capabilities.operandPerformance.asVector().end(),
                  std::back_inserter(operandPerformance),
                  [](const nn::Capabilities::OperandPerformance& operandPerformance) {
-                     return nn::validOperandType(operandPerformance.type);
+                     return compliantVersion(operandPerformance.type).has_value();
                  });
 
     return Capabilities{
@@ -570,6 +519,7 @@
 
 nn::GeneralResult<Timing> unvalidatedConvert(const nn::Timing& timing) {
     constexpr auto convertTiming = [](nn::OptionalDuration canonicalTiming) -> uint64_t {
+        constexpr uint64_t kNoTiming = std::numeric_limits<uint64_t>::max();
         if (!canonicalTiming.has_value()) {
             return kNoTiming;
         }
diff --git a/neuralnetworks/1.2/utils/src/ExecutionBurstController.cpp b/neuralnetworks/1.2/utils/src/ExecutionBurstController.cpp
index eedf591..7a17f25 100644
--- a/neuralnetworks/1.2/utils/src/ExecutionBurstController.cpp
+++ b/neuralnetworks/1.2/utils/src/ExecutionBurstController.cpp
@@ -276,7 +276,9 @@
 }
 
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
-ExecutionBurstController::execute(const nn::Request& request, nn::MeasureTiming measure) const {
+ExecutionBurstController::execute(const nn::Request& request, nn::MeasureTiming measure,
+                                  const nn::OptionalTimePoint& deadline,
+                                  const nn::OptionalDuration& loopTimeoutDuration) const {
     // This is the first point when we know an execution is occurring, so begin to collect
     // systraces. Note that the first point we can begin collecting systraces in
     // ExecutionBurstServer is when the RequestChannelReceiver realizes there is data in the FMQ, so
@@ -289,7 +291,7 @@
         version > nn::Version::ANDROID_Q) {
         // fallback to another execution path if the packet could not be sent
         if (kFallback) {
-            return kFallback(request, measure);
+            return kFallback(request, measure, deadline, loopTimeoutDuration);
         }
         return NN_ERROR() << "Request object has features not supported by IBurst::execute";
     }
@@ -323,7 +325,7 @@
     if (!sendStatus.ok()) {
         // fallback to another execution path if the packet could not be sent
         if (kFallback) {
-            return kFallback(request, measure);
+            return kFallback(request, measure, deadline, loopTimeoutDuration);
         }
         return NN_ERROR() << "Error sending FMQ packet: " << sendStatus.error();
     }
diff --git a/neuralnetworks/1.2/utils/src/ExecutionBurstServer.cpp b/neuralnetworks/1.2/utils/src/ExecutionBurstServer.cpp
index 50af881..c67159e 100644
--- a/neuralnetworks/1.2/utils/src/ExecutionBurstServer.cpp
+++ b/neuralnetworks/1.2/utils/src/ExecutionBurstServer.cpp
@@ -259,7 +259,7 @@
     nn::MeasureTiming canonicalMeasure = NN_TRY(makeExecutionFailure(nn::convert(measure)));
 
     const auto [outputShapes, timing] =
-            NN_TRY(mBurstExecutor->execute(canonicalRequest, canonicalMeasure));
+            NN_TRY(mBurstExecutor->execute(canonicalRequest, canonicalMeasure, {}, {}));
 
     return std::make_pair(NN_TRY(makeExecutionFailure(convert(outputShapes))),
                           NN_TRY(makeExecutionFailure(convert(timing))));
diff --git a/neuralnetworks/1.2/utils/src/ExecutionBurstUtils.cpp b/neuralnetworks/1.2/utils/src/ExecutionBurstUtils.cpp
index ca3a52c..1bdde1e 100644
--- a/neuralnetworks/1.2/utils/src/ExecutionBurstUtils.cpp
+++ b/neuralnetworks/1.2/utils/src/ExecutionBurstUtils.cpp
@@ -520,6 +520,8 @@
             }
             return packet;
         }
+
+        std::this_thread::yield();
     }
 
     // If we get to this point, we either stopped polling because it was taking too long or polling
@@ -665,6 +667,8 @@
             }
             return packet;
         }
+
+        std::this_thread::yield();
     }
 
     // If we get to this point, we either stopped polling because it was taking too long or polling
diff --git a/neuralnetworks/1.2/utils/src/PreparedModel.cpp b/neuralnetworks/1.2/utils/src/PreparedModel.cpp
index 71a4ea8..b209a44 100644
--- a/neuralnetworks/1.2/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/1.2/utils/src/PreparedModel.cpp
@@ -122,10 +122,12 @@
 
 nn::GeneralResult<nn::SharedBurst> PreparedModel::configureExecutionBurst() const {
     auto self = shared_from_this();
-    auto fallback = [preparedModel = std::move(self)](const nn::Request& request,
-                                                      nn::MeasureTiming measure)
+    auto fallback = [preparedModel = std::move(self)](
+                            const nn::Request& request, nn::MeasureTiming measure,
+                            const nn::OptionalTimePoint& deadline,
+                            const nn::OptionalDuration& loopTimeoutDuration)
             -> nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> {
-        return preparedModel->execute(request, measure, {}, {});
+        return preparedModel->execute(request, measure, deadline, loopTimeoutDuration);
     };
     const auto pollingTimeWindow = getBurstControllerPollingTimeWindow();
     return ExecutionBurstController::create(kPreparedModel, std::move(fallback), pollingTimeWindow);
diff --git a/neuralnetworks/1.2/utils/test/MockBurstContext.h b/neuralnetworks/1.2/utils/test/MockBurstContext.h
new file mode 100644
index 0000000..e364178
--- /dev/null
+++ b/neuralnetworks/1.2/utils/test/MockBurstContext.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_TEST_MOCK_BURST_CONTEXT_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_TEST_MOCK_BURST_CONTEXT_H
+
+#include <android/hardware/neuralnetworks/1.2/IBurstContext.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/Status.h>
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+
+class MockBurstContext final : public IBurstContext {
+  public:
+    // V1_2 methods below.
+    MOCK_METHOD(Return<void>, freeMemory, (int32_t slot), (override));
+};
+
+}  // namespace android::hardware::neuralnetworks::V1_2::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_TEST_MOCK_BURST_CONTEXT_H
diff --git a/neuralnetworks/1.2/utils/test/MockDevice.h b/neuralnetworks/1.2/utils/test/MockDevice.h
index b459943..0d34c70 100644
--- a/neuralnetworks/1.2/utils/test/MockDevice.h
+++ b/neuralnetworks/1.2/utils/test/MockDevice.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_TEST_MOCK_DEVICE
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_TEST_MOCK_DEVICE
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_TEST_MOCK_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_TEST_MOCK_DEVICE_H
 
 #include <android/hardware/neuralnetworks/1.2/IDevice.h>
 #include <gmock/gmock.h>
@@ -114,4 +114,4 @@
 
 }  // namespace android::hardware::neuralnetworks::V1_2::utils
 
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_TEST_MOCK_DEVICE
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_TEST_MOCK_DEVICE_H
diff --git a/neuralnetworks/1.2/utils/test/MockPreparedModel.h b/neuralnetworks/1.2/utils/test/MockPreparedModel.h
index f5fd1f3..bd81712 100644
--- a/neuralnetworks/1.2/utils/test/MockPreparedModel.h
+++ b/neuralnetworks/1.2/utils/test/MockPreparedModel.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_TEST_MOCK_PREPARED_MODEL
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_TEST_MOCK_PREPARED_MODEL
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_TEST_MOCK_PREPARED_MODEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_TEST_MOCK_PREPARED_MODEL_H
 
 #include <android/hardware/neuralnetworks/1.2/IPreparedModel.h>
 #include <gmock/gmock.h>
@@ -98,4 +98,4 @@
 
 }  // namespace android::hardware::neuralnetworks::V1_2::utils
 
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_TEST_MOCK_PREPARED_MODEL
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_TEST_MOCK_PREPARED_MODEL_H
diff --git a/neuralnetworks/1.2/utils/test/PreparedModelTest.cpp b/neuralnetworks/1.2/utils/test/PreparedModelTest.cpp
index 5062ac9..d297b1a 100644
--- a/neuralnetworks/1.2/utils/test/PreparedModelTest.cpp
+++ b/neuralnetworks/1.2/utils/test/PreparedModelTest.cpp
@@ -16,6 +16,8 @@
 
 #include "MockPreparedModel.h"
 
+#include "MockBurstContext.h"
+
 #include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -67,6 +69,17 @@
         return launchStatus;
     };
 }
+auto makeConfigureExecutionBurstReturn(V1_0::ErrorStatus status,
+                                       const sp<MockBurstContext>& burstContext) {
+    return [status, burstContext](
+                   const sp<V1_2::IBurstCallback>& /*callback*/,
+                   const MQDescriptorSync<V1_2::FmqRequestDatum>& /*requestChannel*/,
+                   const MQDescriptorSync<V1_2::FmqResultDatum>& /*resultChannel*/,
+                   V1_2::IPreparedModel::configureExecutionBurst_cb cb) -> hardware::Return<void> {
+        cb(status, burstContext);
+        return hardware::Void();
+    };
+}
 
 std::function<hardware::Status()> makeTransportFailure(status_t status) {
     return [status] { return hardware::Status::fromStatusT(status); };
@@ -321,7 +334,76 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-// TODO: test burst execution if/when it is added to nn::IPreparedModel.
+TEST(PreparedModelTest, configureExecutionBurst) {
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto mockBurstContext = sp<MockBurstContext>::make();
+    EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_, _, _, _))
+            .Times(1)
+            .WillOnce(makeConfigureExecutionBurstReturn(V1_0::ErrorStatus::NONE, mockBurstContext));
+    const auto preparedModel =
+            PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
+
+    // run test
+    const auto result = preparedModel->configureExecutionBurst();
+
+    // verify result
+    ASSERT_TRUE(result.has_value())
+            << "Failed with " << result.error().code << ": " << result.error().message;
+    EXPECT_NE(result.value(), nullptr);
+}
+
+TEST(PreparedModelTest, configureExecutionBurstError) {
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto preparedModel =
+            PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
+    EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_, _, _, _))
+            .Times(1)
+            .WillOnce(
+                    makeConfigureExecutionBurstReturn(V1_0::ErrorStatus::GENERAL_FAILURE, nullptr));
+
+    // run test
+    const auto result = preparedModel->configureExecutionBurst();
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(PreparedModelTest, configureExecutionBurstTransportFailure) {
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto preparedModel =
+            PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
+    EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_, _, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
+
+    // run test
+    const auto result = preparedModel->configureExecutionBurst();
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(PreparedModelTest, configureExecutionBurstDeadObject) {
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto preparedModel =
+            PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
+    EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_, _, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
+
+    // run test
+    const auto result = preparedModel->configureExecutionBurst();
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
+}
 
 TEST(PreparedModelTest, getUnderlyingResource) {
     // setup test
diff --git a/neuralnetworks/1.3/IDevice.hal b/neuralnetworks/1.3/IDevice.hal
index e0b04a8..de889e4 100644
--- a/neuralnetworks/1.3/IDevice.hal
+++ b/neuralnetworks/1.3/IDevice.hal
@@ -131,6 +131,14 @@
      * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
      * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due
      * to an abort must be sent the same way as other errors, described above.
+     * The deadline is represented as nanoseconds since the epoch of the steady
+     * clock (as if from std::chrono::steady_clock::time_point), but the service
+     * may convert it to the nanoseconds since boot time (as if from
+     * clock_gettime(CLOCK_BOOTTIME, &ts) or
+     * android::base::boot_clock::time_point) to account for time when the
+     * system is suspended. This conversion can by done by finding the timeout
+     * duration remaining compared to the steady_clock and adding it to the
+     * current boot_clock time.
      *
      * Optionally, the driver may save the prepared model to cache during the
      * asynchronous preparation. Any error that occurs when saving to cache must
@@ -249,7 +257,15 @@
      * ErrorStatus::MISSED_DEADLINE_TRANSIENT}
      * or {@link ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The
      * error due to an abort must be sent the same way as other errors,
-     * described above.
+     * described above. The deadline is represented as nanoseconds since the
+     * epoch of the steady clock (as if from
+     * std::chrono::steady_clock::time_point), but the service may convert it to
+     * the nanoseconds since boot time (as if from
+     * clock_gettime(CLOCK_BOOTTIME, &ts) or
+     * android::base::boot_clock::time_point) to account for time when the
+     * system is suspended. This conversion can by done by finding the timeout
+     * duration remaining compared to the steady_clock and adding it to the
+     * current boot_clock time.
      *
      * The only information that may be unknown to the model at this stage is
      * the shape of the tensors, which may only be known at execution time. As
diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal
index e7d63f4..8b86a1a 100644
--- a/neuralnetworks/1.3/IPreparedModel.hal
+++ b/neuralnetworks/1.3/IPreparedModel.hal
@@ -74,6 +74,14 @@
      * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
      * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due
      * to an abort must be sent the same way as other errors, described above.
+     * The deadline is represented as nanoseconds since the epoch of the steady
+     * clock (as if from std::chrono::steady_clock::time_point), but the service
+     * may convert it to the nanoseconds since boot time (as if from
+     * clock_gettime(CLOCK_BOOTTIME, &ts) or
+     * android::base::boot_clock::time_point) to account for time when the
+     * system is suspended. This conversion can by done by finding the timeout
+     * duration remaining compared to the steady_clock and adding it to the
+     * current boot_clock time.
      *
      * Any number of calls to the execute* and executeSynchronously* functions,
      * in any combination, may be made concurrently, even on the same
@@ -150,6 +158,14 @@
      * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
      * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due
      * to an abort must be sent the same way as other errors, described above.
+     * The deadline is represented as nanoseconds since the epoch of the steady
+     * clock (as if from std::chrono::steady_clock::time_point), but the service
+     * may convert it to the nanoseconds since boot time (as if from
+     * clock_gettime(CLOCK_BOOTTIME, &ts) or
+     * android::base::boot_clock::time_point) to account for time when the
+     * system is suspended. This conversion can by done by finding the timeout
+     * duration remaining compared to the steady_clock and adding it to the
+     * current boot_clock time.
      *
      * Any number of calls to the execute* and executeSynchronously* functions,
      * in any combination, may be made concurrently, even on the same
@@ -231,6 +247,14 @@
      * {@link ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link
      * ErrorStatus::MISSED_DEADLINE_PERSISTENT} may be returned. The error due
      * to an abort must be sent the same way as other errors, described above.
+     * The deadline is represented as nanoseconds since the epoch of the steady
+     * clock (as if from std::chrono::steady_clock::time_point), but the service
+     * may convert it to the nanoseconds since boot time (as if from
+     * clock_gettime(CLOCK_BOOTTIME, &ts) or
+     * android::base::boot_clock::time_point) to account for time when the
+     * system is suspended. This conversion can by done by finding the timeout
+     * duration remaining compared to the steady_clock and adding it to the
+     * current boot_clock time.
      *
      * If any of the sync fences in waitFor changes to error status after the executeFenced
      * call succeeds, or the execution is aborted because it cannot finish before the deadline
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h
index 3ce412c..1d76caa 100644
--- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h
@@ -22,14 +22,25 @@
 #include <android-base/logging.h>
 #include <android/hardware/neuralnetworks/1.3/types.h>
 #include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
 #include <nnapi/Types.h>
+#include <nnapi/Validation.h>
 #include <nnapi/hal/1.0/Conversions.h>
 #include <nnapi/hal/1.1/Conversions.h>
+#include <nnapi/hal/1.1/Utils.h>
 #include <nnapi/hal/1.2/Conversions.h>
+#include <nnapi/hal/1.2/Utils.h>
+#include <nnapi/hal/HandleError.h>
 
 namespace android::hardware::neuralnetworks::V1_3::utils {
 
+using V1_1::utils::kDefaultExecutionPreference;
+using V1_2::utils::CacheToken;
+using V1_2::utils::kDefaultMesaureTiming;
+using V1_2::utils::kNoTiming;
+
 constexpr auto kDefaultPriority = Priority::MEDIUM;
+constexpr auto kVersion = nn::Version::ANDROID_R;
 
 template <typename Type>
 nn::Result<void> validate(const Type& halObject) {
@@ -50,6 +61,15 @@
 }
 
 template <typename Type>
+nn::GeneralResult<void> compliantVersion(const Type& canonical) {
+    const auto version = NN_TRY(hal::utils::makeGeneralFailure(nn::validate(canonical)));
+    if (version > kVersion) {
+        return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
+    }
+    return {};
+}
+
+template <typename Type>
 auto convertFromNonCanonical(const Type& nonCanonicalObject)
         -> decltype(convert(nn::convert(nonCanonicalObject).value())) {
     return convert(NN_TRY(nn::convert(nonCanonicalObject)));
diff --git a/neuralnetworks/1.3/utils/src/Conversions.cpp b/neuralnetworks/1.3/utils/src/Conversions.cpp
index 9788fe1..e8a4f55 100644
--- a/neuralnetworks/1.3/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.3/utils/src/Conversions.cpp
@@ -38,55 +38,47 @@
 #include <type_traits>
 #include <utility>
 
+#include "Utils.h"
+
 namespace {
 
+std::chrono::nanoseconds makeNanosFromUint64(uint64_t nanoseconds) {
+    constexpr auto kMaxCount = std::chrono::nanoseconds::max().count();
+    using CommonType = std::common_type_t<std::chrono::nanoseconds::rep, uint64_t>;
+    const auto count = std::min<CommonType>(kMaxCount, nanoseconds);
+    return std::chrono::nanoseconds{static_cast<std::chrono::nanoseconds::rep>(count)};
+}
+
+uint64_t makeUint64FromNanos(std::chrono::nanoseconds nanoseconds) {
+    if (nanoseconds < std::chrono::nanoseconds::zero()) {
+        return 0;
+    }
+    constexpr auto kMaxCount = std::numeric_limits<uint64_t>::max();
+    using CommonType = std::common_type_t<std::chrono::nanoseconds::rep, uint64_t>;
+    const auto count = std::min<CommonType>(kMaxCount, nanoseconds.count());
+    return static_cast<uint64_t>(count);
+}
+
 template <typename Type>
 constexpr std::underlying_type_t<Type> underlyingType(Type value) {
     return static_cast<std::underlying_type_t<Type>>(value);
 }
 
-constexpr auto kVersion = android::nn::Version::ANDROID_R;
-
 }  // namespace
 
 namespace android::nn {
 namespace {
 
-constexpr auto validOperandType(nn::OperandType operandType) {
-    switch (operandType) {
-        case nn::OperandType::FLOAT32:
-        case nn::OperandType::INT32:
-        case nn::OperandType::UINT32:
-        case nn::OperandType::TENSOR_FLOAT32:
-        case nn::OperandType::TENSOR_INT32:
-        case nn::OperandType::TENSOR_QUANT8_ASYMM:
-        case nn::OperandType::BOOL:
-        case nn::OperandType::TENSOR_QUANT16_SYMM:
-        case nn::OperandType::TENSOR_FLOAT16:
-        case nn::OperandType::TENSOR_BOOL8:
-        case nn::OperandType::FLOAT16:
-        case nn::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
-        case nn::OperandType::TENSOR_QUANT16_ASYMM:
-        case nn::OperandType::TENSOR_QUANT8_SYMM:
-        case nn::OperandType::TENSOR_QUANT8_ASYMM_SIGNED:
-        case nn::OperandType::SUBGRAPH:
-        case nn::OperandType::OEM:
-        case nn::OperandType::TENSOR_OEM_BYTE:
-            return true;
-    }
-    return nn::isExtension(operandType);
-}
-
 using hardware::hidl_vec;
 
 template <typename Input>
-using unvalidatedConvertOutput =
+using UnvalidatedConvertOutput =
         std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
 
 template <typename Type>
-GeneralResult<std::vector<unvalidatedConvertOutput<Type>>> unvalidatedConvertVec(
+GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> unvalidatedConvert(
         const hidl_vec<Type>& arguments) {
-    std::vector<unvalidatedConvertOutput<Type>> canonical;
+    std::vector<UnvalidatedConvertOutput<Type>> canonical;
     canonical.reserve(arguments.size());
     for (const auto& argument : arguments) {
         canonical.push_back(NN_TRY(nn::unvalidatedConvert(argument)));
@@ -95,29 +87,16 @@
 }
 
 template <typename Type>
-GeneralResult<std::vector<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
-        const hidl_vec<Type>& arguments) {
-    return unvalidatedConvertVec(arguments);
-}
-
-template <typename Type>
-decltype(nn::unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& halObject) {
+GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& halObject) {
     auto canonical = NN_TRY(nn::unvalidatedConvert(halObject));
-    const auto maybeVersion = validate(canonical);
-    if (!maybeVersion.has_value()) {
-        return error() << maybeVersion.error();
-    }
-    const auto version = maybeVersion.value();
-    if (version > kVersion) {
-        return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
-    }
+    NN_TRY(hal::V1_3::utils::compliantVersion(canonical));
     return canonical;
 }
 
 template <typename Type>
-GeneralResult<std::vector<unvalidatedConvertOutput<Type>>> validatedConvert(
+GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> validatedConvert(
         const hidl_vec<Type>& arguments) {
-    std::vector<unvalidatedConvertOutput<Type>> canonical;
+    std::vector<UnvalidatedConvertOutput<Type>> canonical;
     canonical.reserve(arguments.size());
     for (const auto& argument : arguments) {
         canonical.push_back(NN_TRY(validatedConvert(argument)));
@@ -143,8 +122,7 @@
     const bool validOperandTypes = std::all_of(
             capabilities.operandPerformance.begin(), capabilities.operandPerformance.end(),
             [](const hal::V1_3::Capabilities::OperandPerformance& operandPerformance) {
-                const auto maybeType = unvalidatedConvert(operandPerformance.type);
-                return !maybeType.has_value() ? false : validOperandType(maybeType.value());
+                return validatedConvert(operandPerformance.type).has_value();
             });
     if (!validOperandTypes) {
         return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
@@ -244,7 +222,7 @@
     return BufferRole{
             .modelIndex = bufferRole.modelIndex,
             .ioIndex = bufferRole.ioIndex,
-            .frequency = bufferRole.frequency,
+            .probability = bufferRole.frequency,
     };
 }
 
@@ -276,8 +254,32 @@
     switch (optionalTimePoint.getDiscriminator()) {
         case Discriminator::none:
             return {};
-        case Discriminator::nanosecondsSinceEpoch:
-            return TimePoint{Duration{optionalTimePoint.nanosecondsSinceEpoch()}};
+        case Discriminator::nanosecondsSinceEpoch: {
+            const auto currentSteadyTime = std::chrono::steady_clock::now();
+            const auto currentBootTime = Clock::now();
+
+            const auto timeSinceEpoch =
+                    makeNanosFromUint64(optionalTimePoint.nanosecondsSinceEpoch());
+            const auto steadyTimePoint = std::chrono::steady_clock::time_point{timeSinceEpoch};
+
+            // Both steadyTimePoint and currentSteadyTime are guaranteed to be non-negative, so this
+            // subtraction will never overflow or underflow.
+            const auto timeRemaining = steadyTimePoint - currentSteadyTime;
+
+            // currentBootTime is guaranteed to be non-negative, so this code only protects against
+            // an overflow.
+            nn::TimePoint bootTimePoint;
+            constexpr auto kZeroNano = std::chrono::nanoseconds::zero();
+            constexpr auto kMaxTime = nn::TimePoint::max();
+            if (timeRemaining > kZeroNano && currentBootTime > kMaxTime - timeRemaining) {
+                bootTimePoint = kMaxTime;
+            } else {
+                bootTimePoint = currentBootTime + timeRemaining;
+            }
+
+            constexpr auto kZeroTime = nn::TimePoint{};
+            return std::max(bootTimePoint, kZeroTime);
+        }
     }
     return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
            << "Invalid OptionalTimePoint discriminator "
@@ -401,25 +403,19 @@
 }
 
 template <typename Input>
-using unvalidatedConvertOutput =
+using UnvalidatedConvertOutput =
         std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
 
 template <typename Type>
-nn::GeneralResult<hidl_vec<unvalidatedConvertOutput<Type>>> unvalidatedConvertVec(
+nn::GeneralResult<hidl_vec<UnvalidatedConvertOutput<Type>>> unvalidatedConvert(
         const std::vector<Type>& arguments) {
-    hidl_vec<unvalidatedConvertOutput<Type>> halObject(arguments.size());
+    hidl_vec<UnvalidatedConvertOutput<Type>> halObject(arguments.size());
     for (size_t i = 0; i < arguments.size(); ++i) {
         halObject[i] = NN_TRY(unvalidatedConvert(arguments[i]));
     }
     return halObject;
 }
 
-template <typename Type>
-nn::GeneralResult<hidl_vec<unvalidatedConvertOutput<Type>>> unvalidatedConvert(
-        const std::vector<Type>& arguments) {
-    return unvalidatedConvertVec(arguments);
-}
-
 nn::GeneralResult<Request::MemoryPool> makeMemoryPool(const nn::SharedMemory& memory) {
     Request::MemoryPool ret;
     ret.hidlMemory(NN_TRY(unvalidatedConvert(memory)));
@@ -439,22 +435,15 @@
 using utils::unvalidatedConvert;
 
 template <typename Type>
-decltype(unvalidatedConvert(std::declval<Type>())) validatedConvert(const Type& canonical) {
-    const auto maybeVersion = nn::validate(canonical);
-    if (!maybeVersion.has_value()) {
-        return nn::error() << maybeVersion.error();
-    }
-    const auto version = maybeVersion.value();
-    if (version > kVersion) {
-        return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
-    }
+nn::GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& canonical) {
+    NN_TRY(compliantVersion(canonical));
     return unvalidatedConvert(canonical);
 }
 
 template <typename Type>
-nn::GeneralResult<hidl_vec<unvalidatedConvertOutput<Type>>> validatedConvert(
+nn::GeneralResult<hidl_vec<UnvalidatedConvertOutput<Type>>> validatedConvert(
         const std::vector<Type>& arguments) {
-    hidl_vec<unvalidatedConvertOutput<Type>> halObject(arguments.size());
+    hidl_vec<UnvalidatedConvertOutput<Type>> halObject(arguments.size());
     for (size_t i = 0; i < arguments.size(); ++i) {
         halObject[i] = NN_TRY(validatedConvert(arguments[i]));
     }
@@ -482,7 +471,7 @@
                  capabilities.operandPerformance.asVector().end(),
                  std::back_inserter(operandPerformance),
                  [](const nn::Capabilities::OperandPerformance& operandPerformance) {
-                     return nn::validOperandType(operandPerformance.type);
+                     return compliantVersion(operandPerformance.type).has_value();
                  });
 
     return Capabilities{
@@ -577,7 +566,7 @@
     return BufferRole{
             .modelIndex = bufferRole.modelIndex,
             .ioIndex = bufferRole.ioIndex,
-            .frequency = bufferRole.frequency,
+            .frequency = bufferRole.probability,
     };
 }
 
@@ -601,9 +590,33 @@
 
 nn::GeneralResult<OptionalTimePoint> unvalidatedConvert(
         const nn::OptionalTimePoint& optionalTimePoint) {
+    const auto currentSteadyTime = std::chrono::steady_clock::now();
+    const auto currentBootTime = nn::Clock::now();
+
     OptionalTimePoint ret;
     if (optionalTimePoint.has_value()) {
-        const auto count = optionalTimePoint.value().time_since_epoch().count();
+        const auto bootTimePoint = optionalTimePoint.value();
+
+        if (bootTimePoint < nn::TimePoint{}) {
+            return NN_ERROR() << "Trying to cast invalid time point";
+        }
+
+        // Both bootTimePoint and currentBootTime are guaranteed to be non-negative, so this
+        // subtraction will never overflow or underflow.
+        const auto timeRemaining = bootTimePoint - currentBootTime;
+
+        // currentSteadyTime is guaranteed to be non-negative, so this code only protects against an
+        // overflow.
+        std::chrono::steady_clock::time_point steadyTimePoint;
+        constexpr auto kZeroNano = std::chrono::nanoseconds::zero();
+        constexpr auto kMaxTime = std::chrono::steady_clock::time_point::max();
+        if (timeRemaining > kZeroNano && currentSteadyTime > kMaxTime - timeRemaining) {
+            steadyTimePoint = kMaxTime;
+        } else {
+            steadyTimePoint = currentSteadyTime + timeRemaining;
+        }
+
+        const uint64_t count = makeUint64FromNanos(steadyTimePoint.time_since_epoch());
         ret.nanosecondsSinceEpoch(count);
     }
     return ret;
diff --git a/neuralnetworks/1.3/utils/src/PreparedModel.cpp b/neuralnetworks/1.3/utils/src/PreparedModel.cpp
index 64275a3..fd7f8f2 100644
--- a/neuralnetworks/1.3/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/1.3/utils/src/PreparedModel.cpp
@@ -201,10 +201,12 @@
 
 nn::GeneralResult<nn::SharedBurst> PreparedModel::configureExecutionBurst() const {
     auto self = shared_from_this();
-    auto fallback = [preparedModel = std::move(self)](const nn::Request& request,
-                                                      nn::MeasureTiming measure)
+    auto fallback = [preparedModel = std::move(self)](
+                            const nn::Request& request, nn::MeasureTiming measure,
+                            const nn::OptionalTimePoint& deadline,
+                            const nn::OptionalDuration& loopTimeoutDuration)
             -> nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> {
-        return preparedModel->execute(request, measure, {}, {});
+        return preparedModel->execute(request, measure, deadline, loopTimeoutDuration);
     };
     const auto pollingTimeWindow = V1_2::utils::getBurstControllerPollingTimeWindow();
     return V1_2::utils::ExecutionBurstController::create(kPreparedModel, std::move(fallback),
diff --git a/neuralnetworks/1.3/utils/test/MockBuffer.h b/neuralnetworks/1.3/utils/test/MockBuffer.h
index fb31b51..a67c5f6 100644
--- a/neuralnetworks/1.3/utils/test/MockBuffer.h
+++ b/neuralnetworks/1.3/utils/test/MockBuffer.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_BUFFER
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_BUFFER
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_BUFFER_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_BUFFER_H
 
 #include <android/hardware/neuralnetworks/1.3/IBuffer.h>
 #include <gmock/gmock.h>
@@ -40,4 +40,4 @@
 
 }  // namespace android::hardware::neuralnetworks::V1_3::utils
 
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_BUFFER
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_BUFFER_H
diff --git a/neuralnetworks/1.3/utils/test/MockBurstContext.h b/neuralnetworks/1.3/utils/test/MockBurstContext.h
new file mode 100644
index 0000000..e102b46
--- /dev/null
+++ b/neuralnetworks/1.3/utils/test/MockBurstContext.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_BURST_CONTEXT_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_BURST_CONTEXT_H
+
+#include <android/hardware/neuralnetworks/1.2/IBurstContext.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/Status.h>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+
+class MockBurstContext final : public V1_2::IBurstContext {
+  public:
+    // V1_2 methods below.
+    MOCK_METHOD(Return<void>, freeMemory, (int32_t slot), (override));
+};
+
+}  // namespace android::hardware::neuralnetworks::V1_3::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_BURST_CONTEXT_H
diff --git a/neuralnetworks/1.3/utils/test/MockDevice.h b/neuralnetworks/1.3/utils/test/MockDevice.h
index 85d3750..b79037f 100644
--- a/neuralnetworks/1.3/utils/test/MockDevice.h
+++ b/neuralnetworks/1.3/utils/test/MockDevice.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_DEVICE
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_DEVICE
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_DEVICE_H
 
 #include <android/hardware/neuralnetworks/1.3/IDevice.h>
 #include <gmock/gmock.h>
@@ -136,4 +136,4 @@
 
 }  // namespace android::hardware::neuralnetworks::V1_3::utils
 
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_DEVICE
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_DEVICE_H
diff --git a/neuralnetworks/1.3/utils/test/MockFencedExecutionCallback.h b/neuralnetworks/1.3/utils/test/MockFencedExecutionCallback.h
index fc08a7f..04c0a92 100644
--- a/neuralnetworks/1.3/utils/test/MockFencedExecutionCallback.h
+++ b/neuralnetworks/1.3/utils/test/MockFencedExecutionCallback.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_FENCED_EXECUTION_CALLBACK
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_FENCED_EXECUTION_CALLBACK
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_FENCED_EXECUTION_CALLBACK_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_FENCED_EXECUTION_CALLBACK_H
 
 #include <android/hardware/neuralnetworks/1.3/IFencedExecutionCallback.h>
 #include <gmock/gmock.h>
@@ -39,4 +39,4 @@
 
 }  // namespace android::hardware::neuralnetworks::V1_3::utils
 
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_FENCED_EXECUTION_CALLBACK
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_FENCED_EXECUTION_CALLBACK_H
diff --git a/neuralnetworks/1.3/utils/test/MockPreparedModel.h b/neuralnetworks/1.3/utils/test/MockPreparedModel.h
index e441524..ef64fa4 100644
--- a/neuralnetworks/1.3/utils/test/MockPreparedModel.h
+++ b/neuralnetworks/1.3/utils/test/MockPreparedModel.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_PREPARED_MODEL
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_PREPARED_MODEL
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_PREPARED_MODEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_PREPARED_MODEL_H
 
 #include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
 #include <gmock/gmock.h>
@@ -118,4 +118,4 @@
 
 }  // namespace android::hardware::neuralnetworks::V1_3::utils
 
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_PREPARED_MODEL
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_TEST_MOCK_PREPARED_MODEL_H
diff --git a/neuralnetworks/1.3/utils/test/PreparedModelTest.cpp b/neuralnetworks/1.3/utils/test/PreparedModelTest.cpp
index 11796dd..5303c2a 100644
--- a/neuralnetworks/1.3/utils/test/PreparedModelTest.cpp
+++ b/neuralnetworks/1.3/utils/test/PreparedModelTest.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "MockBurstContext.h"
 #include "MockFencedExecutionCallback.h"
 #include "MockPreparedModel.h"
 
@@ -96,6 +97,17 @@
         return hardware::Void();
     };
 }
+auto makeConfigureExecutionBurstReturn(V1_0::ErrorStatus status,
+                                       const sp<MockBurstContext>& burstContext) {
+    return [status, burstContext](
+                   const sp<V1_2::IBurstCallback>& /*callback*/,
+                   const MQDescriptorSync<V1_2::FmqRequestDatum>& /*requestChannel*/,
+                   const MQDescriptorSync<V1_2::FmqResultDatum>& /*resultChannel*/,
+                   V1_2::IPreparedModel::configureExecutionBurst_cb cb) -> hardware::Return<void> {
+        cb(status, burstContext);
+        return hardware::Void();
+    };
+}
 
 std::function<hardware::Status()> makeTransportFailure(status_t status) {
     return [status] { return hardware::Status::fromStatusT(status); };
@@ -450,7 +462,76 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-// TODO: test burst execution if/when it is added to nn::IPreparedModel.
+TEST(PreparedModelTest, configureExecutionBurst) {
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto mockBurstContext = sp<MockBurstContext>::make();
+    EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_, _, _, _))
+            .Times(1)
+            .WillOnce(makeConfigureExecutionBurstReturn(V1_0::ErrorStatus::NONE, mockBurstContext));
+    const auto preparedModel =
+            PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
+
+    // run test
+    const auto result = preparedModel->configureExecutionBurst();
+
+    // verify result
+    ASSERT_TRUE(result.has_value())
+            << "Failed with " << result.error().code << ": " << result.error().message;
+    EXPECT_NE(result.value(), nullptr);
+}
+
+TEST(PreparedModelTest, configureExecutionBurstError) {
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto preparedModel =
+            PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
+    EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_, _, _, _))
+            .Times(1)
+            .WillOnce(
+                    makeConfigureExecutionBurstReturn(V1_0::ErrorStatus::GENERAL_FAILURE, nullptr));
+
+    // run test
+    const auto result = preparedModel->configureExecutionBurst();
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(PreparedModelTest, configureExecutionBurstTransportFailure) {
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto preparedModel =
+            PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
+    EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_, _, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
+
+    // run test
+    const auto result = preparedModel->configureExecutionBurst();
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(PreparedModelTest, configureExecutionBurstDeadObject) {
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto preparedModel =
+            PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
+    EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_, _, _, _))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
+
+    // run test
+    const auto result = preparedModel->configureExecutionBurst();
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
+}
 
 TEST(PreparedModelTest, getUnderlyingResource) {
     // setup test
diff --git a/neuralnetworks/aidl/Android.bp b/neuralnetworks/aidl/Android.bp
index b1860e2..ebf4654 100644
--- a/neuralnetworks/aidl/Android.bp
+++ b/neuralnetworks/aidl/Android.bp
@@ -16,6 +16,7 @@
     stability: "vintf",
     imports: [
         "android.hardware.common",
+        "android.hardware.graphics.common",
     ],
     backend: {
         java: {
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/BufferRole.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/BufferRole.aidl
index f18e92a..10a6b75 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/BufferRole.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/BufferRole.aidl
@@ -36,5 +36,5 @@
 parcelable BufferRole {
   int modelIndex;
   int ioIndex;
-  float frequency;
+  float probability;
 }
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBurst.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBurst.aidl
index 634f39e..eb3d0b0 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBurst.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IBurst.aidl
@@ -34,6 +34,6 @@
 package android.hardware.neuralnetworks;
 @VintfStability
 interface IBurst {
-  android.hardware.neuralnetworks.ExecutionResult executeSynchronously(in android.hardware.neuralnetworks.Request request, in long[] memoryIdentifierTokens, in boolean measureTiming, in long deadline, in long loopTimeoutDuration);
+  android.hardware.neuralnetworks.ExecutionResult executeSynchronously(in android.hardware.neuralnetworks.Request request, in long[] memoryIdentifierTokens, in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs);
   void releaseMemoryResource(in long memoryIdentifierToken);
 }
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl
index b328b29..c9c67f2 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IDevice.aidl
@@ -41,8 +41,8 @@
   boolean[] getSupportedOperations(in android.hardware.neuralnetworks.Model model);
   android.hardware.neuralnetworks.DeviceType getType();
   String getVersionString();
-  void prepareModel(in android.hardware.neuralnetworks.Model model, in android.hardware.neuralnetworks.ExecutionPreference preference, in android.hardware.neuralnetworks.Priority priority, in long deadline, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache, in byte[] token, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
-  void prepareModelFromCache(in long deadline, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache, in byte[] token, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
+  void prepareModel(in android.hardware.neuralnetworks.Model model, in android.hardware.neuralnetworks.ExecutionPreference preference, in android.hardware.neuralnetworks.Priority priority, in long deadlineNs, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache, in byte[] token, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
+  void prepareModelFromCache(in long deadlineNs, in ParcelFileDescriptor[] modelCache, in ParcelFileDescriptor[] dataCache, in byte[] token, in android.hardware.neuralnetworks.IPreparedModelCallback callback);
   const int BYTE_SIZE_OF_CACHE_TOKEN = 32;
   const int MAX_NUMBER_OF_CACHE_FILES = 32;
   const int EXTENSION_TYPE_HIGH_BITS_PREFIX = 15;
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl
index 52882cd..fccb5dc 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/IPreparedModel.aidl
@@ -34,8 +34,8 @@
 package android.hardware.neuralnetworks;
 @VintfStability
 interface IPreparedModel {
-  android.hardware.neuralnetworks.ExecutionResult executeSynchronously(in android.hardware.neuralnetworks.Request request, in boolean measureTiming, in long deadline, in long loopTimeoutDuration);
-  android.hardware.neuralnetworks.FencedExecutionResult executeFenced(in android.hardware.neuralnetworks.Request request, in ParcelFileDescriptor[] waitFor, in boolean measureTiming, in long deadline, in long loopTimeoutDuration, in long duration);
+  android.hardware.neuralnetworks.ExecutionResult executeSynchronously(in android.hardware.neuralnetworks.Request request, in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs);
+  android.hardware.neuralnetworks.FencedExecutionResult executeFenced(in android.hardware.neuralnetworks.Request request, in ParcelFileDescriptor[] waitFor, in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs, in long durationNs);
   android.hardware.neuralnetworks.IBurst configureExecutionBurst();
   const long DEFAULT_LOOP_TIMEOUT_DURATION_NS = 2000000000;
   const long MAXIMUM_LOOP_TIMEOUT_DURATION_NS = 15000000000;
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Memory.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Memory.aidl
index 8207b25..37fa102 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Memory.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Memory.aidl
@@ -33,8 +33,8 @@
 
 package android.hardware.neuralnetworks;
 @VintfStability
-parcelable Memory {
-  android.hardware.common.NativeHandle handle;
-  long size;
-  String name;
+union Memory {
+  android.hardware.common.Ashmem ashmem;
+  android.hardware.common.MappableFile mappableFile;
+  android.hardware.graphics.common.HardwareBuffer hardwareBuffer;
 }
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Timing.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Timing.aidl
index 9690e01..bcc83cf 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Timing.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Timing.aidl
@@ -34,6 +34,6 @@
 package android.hardware.neuralnetworks;
 @VintfStability
 parcelable Timing {
-  long timeOnDevice;
-  long timeInDriver;
+  long timeOnDeviceNs;
+  long timeInDriverNs;
 }
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/BufferRole.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/BufferRole.aidl
index 0d7f678..c444851 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/BufferRole.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/BufferRole.aidl
@@ -35,5 +35,5 @@
      * used in the specified role. This is provided as a hint to optimize the case when multiple
      * roles prefer different buffer locations or data layouts.
      */
-    float frequency;
+    float probability;
 }
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/FusedActivationFunc.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/FusedActivationFunc.aidl
index 861b6f0..df015ca 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/FusedActivationFunc.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/FusedActivationFunc.aidl
@@ -22,8 +22,20 @@
 @VintfStability
 @Backing(type="int")
 enum FusedActivationFunc {
+    /**
+     * No activation.
+     */
     NONE,
+    /**
+     * ReLU(x) = max(0, x)
+     */
     RELU,
+    /**
+     * ReLU1(x) = min(1, max(-1, x))
+     */
     RELU1,
+    /**
+     * ReLU6(x) = min(6, max(0, x))
+     */
     RELU6,
 }
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IBurst.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IBurst.aidl
index 85d2a03..decdc48 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IBurst.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IBurst.aidl
@@ -77,18 +77,18 @@
      * @param measure Specifies whether or not to measure duration of the execution. The duration
      *                runs from the time the driver sees the call to the executeSynchronously
      *                function to the time the driver returns from the function.
-     * @param deadline The time by which the execution is expected to complete. The time is measured
-     *                 in nanoseconds since epoch of the steady clock (as from
-     *                 std::chrono::steady_clock). If the execution cannot be finished by the
-     *                 deadline, the execution may be aborted. Passing -1 means the deadline is
-     *                 omitted. Other negative values are invalid.
-     * @param loopTimeoutDuration The maximum amount of time in nanoseconds that should be spent
-     *                            executing a {@link OperationType::WHILE} operation. If a loop
-     *                            condition model does not output false within this duration, the
-     *                            execution must be aborted. If -1 is provided, the maximum amount
-     *                            of time is {@link DEFAULT_LOOP_TIMEOUT_DURATION_NS}. Other
-     *                            negative values are invalid. When provided, the duration must not
-     *                            exceed {@link MAXIMUM_LOOP_TIMEOUT_DURATION_NS}.
+     * @param deadlineNs The time by which the execution is expected to complete. The time is
+     *                   measured in nanoseconds since epoch of the steady clock (as from
+     *                   std::chrono::steady_clock). If the execution cannot be finished by the
+     *                   deadline, the execution may be aborted. Passing -1 means the deadline is
+     *                   omitted. Other negative values are invalid.
+     * @param loopTimeoutDurationNs The maximum amount of time in nanoseconds that should be spent
+     *                              executing a {@link OperationType::WHILE} operation. If a loop
+     *                              condition model does not output false within this duration, the
+     *                              execution must be aborted. If -1 is provided, the maximum amount
+     *                              of time is {@link DEFAULT_LOOP_TIMEOUT_DURATION_NS}. Other
+     *                              negative values are invalid. When provided, the duration must
+     *                              not exceed {@link MAXIMUM_LOOP_TIMEOUT_DURATION_NS}.
      * @return ExecutionResult parcelable, containing the status of the execution, output shapes and
      *     timing information.
      * @throws ServiceSpecificException with one of the following ErrorStatus values:
@@ -100,7 +100,7 @@
      *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
      */
     ExecutionResult executeSynchronously(in Request request, in long[] memoryIdentifierTokens,
-            in boolean measureTiming, in long deadline, in long loopTimeoutDuration);
+            in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs);
 
     /**
      * releaseMemoryResource is used by the client to signal to the service that a memory buffer
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl
index e17e0cd..72e2623 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IDevice.aidl
@@ -306,11 +306,11 @@
      * @param preference Indicates the intended execution behavior of a prepared model.
      * @param priority The priority of the prepared model relative to other prepared models owned by
      *                 the client.
-     * @param deadline The time by which the model is expected to be prepared. The time is measured
-     *                 in nanoseconds since epoch of the steady clock (as from
-     *                 std::chrono::steady_clock). If the model cannot be prepared by the deadline,
-     *                 the preparation may be aborted. Passing -1 means the deadline is omitted.
-     *                 Other negative values are invalid.
+     * @param deadlineNs The time by which the model is expected to be prepared. The time is
+     *                   measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+     *                   &ts) or ::android::base::boot_clock). If the model cannot be prepared by
+     *                   the deadline, the preparation may be aborted. Passing -1 means the deadline
+     *                   is omitted. Other negative values are invalid.
      * @param modelCache A vector of file descriptors for the security-sensitive cache. The length
      *                   of the vector must either be 0 indicating that caching information is not
      *                   provided, or match the numModelCache returned from
@@ -344,7 +344,7 @@
      *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
      */
     void prepareModel(in Model model, in ExecutionPreference preference, in Priority priority,
-            in long deadline, in ParcelFileDescriptor[] modelCache,
+            in long deadlineNs, in ParcelFileDescriptor[] modelCache,
             in ParcelFileDescriptor[] dataCache, in byte[] token,
             in IPreparedModelCallback callback);
 
@@ -395,11 +395,11 @@
      * with a set of inputs to the model. Note that the same prepared model object may be used with
      * different shapes of inputs on different (possibly concurrent) executions.
      *
-     * @param deadline The time by which the model is expected to be prepared. The time is measured
-     *                 in nanoseconds since epoch of the steady clock (as from
-     *                 std::chrono::steady_clock). If the model cannot be prepared by the deadline,
-     *                 the preparation may be aborted. Passing -1 means the deadline is omitted.
-     *                 Other negative values are invalid.
+     * @param deadlineNs The time by which the model is expected to be prepared. The time is
+     *                   measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+     *                   &ts) or ::android::base::boot_clock). If the model cannot be prepared by
+     *                   the deadline, the preparation may be aborted. Passing -1 means the deadline
+     *                   is omitted. Other negative values are invalid.
      * @param modelCache A vector of file descriptors for the security-sensitive cache. The length
      *                   of the vector must match the numModelCache returned from
      *                   getNumberOfCacheFilesNeeded. The cache file descriptors will be provided in
@@ -426,7 +426,7 @@
      *       the deadline
      *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
      */
-    void prepareModelFromCache(in long deadline, in ParcelFileDescriptor[] modelCache,
+    void prepareModelFromCache(in long deadlineNs, in ParcelFileDescriptor[] modelCache,
             in ParcelFileDescriptor[] dataCache, in byte[] token,
             in IPreparedModelCallback callback);
 }
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl
index 2a9757b..956b626 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/IPreparedModel.aidl
@@ -72,18 +72,18 @@
      * @param measure Specifies whether or not to measure duration of the execution. The duration
      *                runs from the time the driver sees the call to the executeSynchronously
      *                function to the time the driver returns from the function.
-     * @param deadline The time by which the execution is expected to complete. The time is measured
-     *                 in nanoseconds since epoch of the steady clock (as from
-     *                 std::chrono::steady_clock). If the execution cannot be finished by the
-     *                 deadline, the execution may be aborted. Passing -1 means the deadline is
-     *                 omitted. Other negative values are invalid.
-     * @param loopTimeoutDuration The maximum amount of time in nanoseconds that should be spent
-     *                            executing a {@link OperationType::WHILE} operation. If a loop
-     *                            condition model does not output false within this duration, the
-     *                            execution must be aborted. If -1 is provided, the maximum amount
-     *                            of time is {@link DEFAULT_LOOP_TIMEOUT_DURATION_NS}. Other
-     *                            negative values are invalid. When provided, the duration must not
-     *                            exceed {@link MAXIMUM_LOOP_TIMEOUT_DURATION_NS}.
+     * @param deadlineNs The time by which the execution is expected to complete. The time is
+     *                   measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+     *                   &ts) or ::android::base::boot_clock). If the execution cannot be finished
+     *                   by the deadline, the execution may be aborted. Passing -1 means the
+     *                   deadline is omitted. Other negative values are invalid.
+     * @param loopTimeoutDurationNs The maximum amount of time in nanoseconds that should be spent
+     *                              executing a {@link OperationType::WHILE} operation. If a loop
+     *                              condition model does not output false within this duration, the
+     *                              execution must be aborted. If -1 is provided, the maximum amount
+     *                              of time is {@link DEFAULT_LOOP_TIMEOUT_DURATION_NS}. Other
+     *                              negative values are invalid. When provided, the duration must
+     *                              not exceed {@link MAXIMUM_LOOP_TIMEOUT_DURATION_NS}.
      * @return ExecutionResult parcelable, containing the status of the execution, output shapes and
      *     timing information.
      * @throws ServiceSpecificException with one of the following ErrorStatus values:
@@ -95,7 +95,7 @@
      *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
      */
     ExecutionResult executeSynchronously(in Request request, in boolean measureTiming,
-            in long deadline, in long loopTimeoutDuration);
+            in long deadlineNs, in long loopTimeoutDurationNs);
 
     /**
      * Launch a fenced asynchronous execution on a prepared model.
@@ -137,22 +137,23 @@
      * @param waitFor A vector of sync fence file descriptors. Execution must not start until all
      *                sync fences have been signaled.
      * @param measure Specifies whether or not to measure duration of the execution.
-     * @param deadline The time by which the execution is expected to complete. The time is measured
-     *                 in nanoseconds since epoch of the steady clock (as from
-     *                 std::chrono::steady_clock).If the execution cannot be finished by the
-     *                 deadline, the execution may be aborted. Passing -1 means the deadline is
-     *                 omitted. Other negative values are invalid.
-     * @param loopTimeoutDuration The maximum amount of time in nanoseconds that should be spent
-     *                            executing a {@link OperationType::WHILE} operation. If a loop
-     *                            condition model does not output false within this duration, the
-     *                            execution must be aborted. If -1 is provided, the maximum amount
-     *                            of time is {@link DEFAULT_LOOP_TIMEOUT_DURATION_NS}. Other
-     *                            negative values are invalid. When provided, the duration must not
-     *                            exceed {@link MAXIMUM_LOOP_TIMEOUT_DURATION_NS}.
-     * @param duration The length of time in nanoseconds within which the execution is expected to
-     *                 complete after all sync fences in waitFor are signaled. If the execution
-     *                 cannot be finished within the duration, the execution may be aborted. Passing
-     *                 -1 means the duration is omitted. Other negative values are invalid.
+     * @param deadlineNs The time by which the execution is expected to complete. The time is
+     *                   measured in nanoseconds since boot (as from clock_gettime(CLOCK_BOOTTIME,
+     *                   &ts) or ::android::base::boot_clock). If the execution cannot be finished
+     *                   by the deadline, the execution may be aborted. Passing -1 means the
+     *                   deadline is omitted. Other negative values are invalid.
+     * @param loopTimeoutDurationNs The maximum amount of time in nanoseconds that should be spent
+     *                              executing a {@link OperationType::WHILE} operation. If a loop
+     *                              condition model does not output false within this duration, the
+     *                              execution must be aborted. If -1 is provided, the maximum amount
+     *                              of time is {@link DEFAULT_LOOP_TIMEOUT_DURATION_NS}. Other
+     *                              negative values are invalid. When provided, the duration must
+     *                              not exceed {@link MAXIMUM_LOOP_TIMEOUT_DURATION_NS}.
+     * @param durationNs The length of time in nanoseconds within which the execution is expected to
+     *                   complete after all sync fences in waitFor are signaled. If the execution
+     *                   cannot be finished within the duration, the execution may be aborted.
+     *                   Passing -1 means the duration is omitted. Other negative values are
+     *                   invalid.
      * @return The FencedExecutionResult parcelable, containing IFencedExecutionCallback and the
      *         sync fence.
      * @throws ServiceSpecificException with one of the following ErrorStatus values:
@@ -165,8 +166,8 @@
      *     - RESOURCE_EXHAUSTED_* if the task was aborted by the driver
      */
     FencedExecutionResult executeFenced(in Request request, in ParcelFileDescriptor[] waitFor,
-            in boolean measureTiming, in long deadline, in long loopTimeoutDuration,
-            in long duration);
+            in boolean measureTiming, in long deadlineNs, in long loopTimeoutDurationNs,
+            in long durationNs);
 
     /**
      * Configure a Burst object used to execute multiple inferences on a prepared model in rapid
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Memory.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Memory.aidl
index 870f0ae..244ac87 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Memory.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Memory.aidl
@@ -15,16 +15,26 @@
  */
 
 package android.hardware.neuralnetworks;
-import android.hardware.common.NativeHandle;
-import android.os.ParcelFileDescriptor;
+
+import android.hardware.common.Ashmem;
+import android.hardware.common.MappableFile;
+import android.hardware.graphics.common.HardwareBuffer;
 
 /**
- * A type that is used to pass pieces of shared memory between processes.
- * The type structure mimics hidl_memory type from HIDL.
+ * The different types of memory that can be shared across processes.
  */
 @VintfStability
-parcelable Memory {
-    NativeHandle handle;
-    long size;
-    String name;
+union Memory {
+    /**
+     * Ashmem hidl_memory type from HIDL.
+     */
+    Ashmem ashmem;
+    /**
+     * File that can be mapped.
+     */
+    MappableFile mappableFile;
+    /**
+     * AIDL representation of AHardwareBuffer.
+     */
+    HardwareBuffer hardwareBuffer;
 }
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Timing.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Timing.aidl
index 8130e08..5225096 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Timing.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Timing.aidl
@@ -28,9 +28,9 @@
     /**
      * Execution time on device (not driver, which runs on host processor).
      */
-    long timeOnDevice;
+    long timeOnDeviceNs;
     /**
      * Execution time in driver (including time on device).
      */
-    long timeInDriver;
+    long timeInDriverNs;
 }
diff --git a/neuralnetworks/aidl/utils/Android.bp b/neuralnetworks/aidl/utils/Android.bp
index 476dac9..0ccc711 100644
--- a/neuralnetworks/aidl/utils/Android.bp
+++ b/neuralnetworks/aidl/utils/Android.bp
@@ -31,10 +31,11 @@
     export_include_dirs: ["include"],
     cflags: ["-Wthread-safety"],
     static_libs: [
+        "android.hardware.graphics.common-V2-ndk_platform",
+        "libaidlcommonsupport",
         "libarect",
         "neuralnetworks_types",
         "neuralnetworks_utils_hal_common",
-        "neuralnetworks_utils_hal_1_0",
     ],
     shared_libs: [
         "android.hardware.neuralnetworks-V1-ndk_platform",
@@ -52,7 +53,9 @@
     ],
     static_libs: [
         "android.hardware.common-V2-ndk_platform",
+        "android.hardware.graphics.common-V2-ndk_platform",
         "android.hardware.neuralnetworks-V1-ndk_platform",
+        "libaidlcommonsupport",
         "libgmock",
         "libneuralnetworks_common",
         "neuralnetworks_types",
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Burst.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Burst.h
new file mode 100644
index 0000000..008e4e4
--- /dev/null
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Burst.h
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_BURST_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_BURST_H
+
+#include <aidl/android/hardware/neuralnetworks/IBurst.h>
+#include <android-base/scopeguard.h>
+#include <android-base/thread_annotations.h>
+#include <nnapi/IBurst.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+
+#include <atomic>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <unordered_map>
+#include <utility>
+
+// See hardware/interfaces/neuralnetworks/utils/README.md for more information on AIDL interface
+// lifetimes across processes and for protecting asynchronous calls across AIDL.
+
+namespace aidl::android::hardware::neuralnetworks::utils {
+
+// Class that adapts aidl_hal::IBurst to nn::IBurst.
+class Burst final : public nn::IBurst {
+    struct PrivateConstructorTag {};
+
+  public:
+    /**
+     * Thread-safe, self-cleaning cache that relates an nn::Memory object to a unique int64_t
+     * identifier.
+     */
+    class MemoryCache : public std::enable_shared_from_this<MemoryCache> {
+      public:
+        using Task = std::function<void()>;
+        using Cleanup = ::android::base::ScopeGuard<Task>;
+        using SharedCleanup = std::shared_ptr<const Cleanup>;
+        using WeakCleanup = std::weak_ptr<const Cleanup>;
+
+        explicit MemoryCache(std::shared_ptr<aidl_hal::IBurst> burst);
+
+        /**
+         * Get or cache a memory object in the MemoryCache object.
+         *
+         * @param memory Memory object to be cached while the returned `SharedCleanup` is alive.
+         * @return A pair of (1) a unique identifier for the cache entry and (2) a ref-counted
+         *     "hold" object which preserves the cache as long as the hold object is alive.
+         */
+        std::pair<int64_t, SharedCleanup> getOrCacheMemory(const nn::SharedMemory& memory);
+
+        /**
+         * Get a cached memory object in the MemoryCache object if it exists, otherwise
+         * std::nullopt.
+         *
+         * @param memory Memory object to be cached while the returned `SharedCleanup` is alive.
+         * @return A pair of (1) a unique identifier for the cache entry and (2) a ref-counted
+         *     "hold" object which preserves the cache as long as the hold object is alive. IF the
+         *     cache entry is not present, std::nullopt is returned instead.
+         */
+        std::optional<std::pair<int64_t, SharedCleanup>> getMemoryIfAvailable(
+                const nn::SharedMemory& memory);
+
+      private:
+        void tryFreeMemory(const nn::SharedMemory& memory, int64_t identifier);
+
+        const std::shared_ptr<aidl_hal::IBurst> kBurst;
+        std::mutex mMutex;
+        int64_t mUnusedIdentifier GUARDED_BY(mMutex) = 0;
+        std::unordered_map<nn::SharedMemory, std::pair<int64_t, WeakCleanup>> mCache
+                GUARDED_BY(mMutex);
+    };
+
+    static nn::GeneralResult<std::shared_ptr<const Burst>> create(
+            std::shared_ptr<aidl_hal::IBurst> burst);
+
+    Burst(PrivateConstructorTag tag, std::shared_ptr<aidl_hal::IBurst> burst);
+
+    // See IBurst::cacheMemory for information.
+    OptionalCacheHold cacheMemory(const nn::SharedMemory& memory) const override;
+
+    // See IBurst::execute for information.
+    nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
+            const nn::Request& request, nn::MeasureTiming measure,
+            const nn::OptionalTimePoint& deadline,
+            const nn::OptionalDuration& loopTimeoutDuration) const override;
+
+  private:
+    mutable std::atomic_flag mExecutionInFlight = ATOMIC_FLAG_INIT;
+    const std::shared_ptr<aidl_hal::IBurst> kBurst;
+    const std::shared_ptr<MemoryCache> kMemoryCache;
+};
+
+}  // namespace aidl::android::hardware::neuralnetworks::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_BURST_H
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
index 4922a6e..5eab9ff 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
@@ -99,6 +99,9 @@
         const ::aidl::android::hardware::common::NativeHandle& handle);
 GeneralResult<SyncFence> unvalidatedConvert(const ndk::ScopedFileDescriptor& syncFence);
 
+GeneralResult<std::vector<Operation>> unvalidatedConvert(
+        const std::vector<aidl_hal::Operation>& operations);
+
 GeneralResult<Capabilities> convert(const aidl_hal::Capabilities& capabilities);
 GeneralResult<DeviceType> convert(const aidl_hal::DeviceType& deviceType);
 GeneralResult<ErrorStatus> convert(const aidl_hal::ErrorStatus& errorStatus);
@@ -106,16 +109,13 @@
         const aidl_hal::ExecutionPreference& executionPreference);
 GeneralResult<SharedMemory> convert(const aidl_hal::Memory& memory);
 GeneralResult<Model> convert(const aidl_hal::Model& model);
-GeneralResult<Operand> convert(const aidl_hal::Operand& operand);
 GeneralResult<OperandType> convert(const aidl_hal::OperandType& operandType);
 GeneralResult<Priority> convert(const aidl_hal::Priority& priority);
-GeneralResult<Request::MemoryPool> convert(const aidl_hal::RequestMemoryPool& memoryPool);
 GeneralResult<Request> convert(const aidl_hal::Request& request);
 GeneralResult<Timing> convert(const aidl_hal::Timing& timing);
 GeneralResult<SyncFence> convert(const ndk::ScopedFileDescriptor& syncFence);
 
 GeneralResult<std::vector<Extension>> convert(const std::vector<aidl_hal::Extension>& extension);
-GeneralResult<std::vector<Operation>> convert(const std::vector<aidl_hal::Operation>& outputShapes);
 GeneralResult<std::vector<SharedMemory>> convert(const std::vector<aidl_hal::Memory>& memories);
 GeneralResult<std::vector<OutputShape>> convert(
         const std::vector<aidl_hal::OutputShape>& outputShapes);
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/InvalidDevice.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/InvalidDevice.h
new file mode 100644
index 0000000..e66507a
--- /dev/null
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/InvalidDevice.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/neuralnetworks/BnBuffer.h>
+#include <aidl/android/hardware/neuralnetworks/BnDevice.h>
+#include <aidl/android/hardware/neuralnetworks/BnPreparedModel.h>
+#include <android/binder_auto_utils.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace aidl::android::hardware::neuralnetworks {
+
+class InvalidDevice : public BnDevice {
+  public:
+    static std::shared_ptr<InvalidDevice> create();
+
+    InvalidDevice(Capabilities capabilities, const NumberOfCacheFiles& numberOfCacheFiles,
+                  std::vector<Extension> extensions, DeviceType deviceType,
+                  std::string versionString);
+
+    ndk::ScopedAStatus allocate(const BufferDesc& desc,
+                                const std::vector<IPreparedModelParcel>& preparedModels,
+                                const std::vector<BufferRole>& inputRoles,
+                                const std::vector<BufferRole>& outputRoles,
+                                DeviceBuffer* deviceBuffer) override;
+    ndk::ScopedAStatus getCapabilities(Capabilities* capabilities) override;
+    ndk::ScopedAStatus getNumberOfCacheFilesNeeded(NumberOfCacheFiles* numberOfCacheFiles) override;
+    ndk::ScopedAStatus getSupportedExtensions(std::vector<Extension>* extensions) override;
+    ndk::ScopedAStatus getSupportedOperations(const Model& model,
+                                              std::vector<bool>* supportedOperations) override;
+    ndk::ScopedAStatus getType(DeviceType* deviceType) override;
+    ndk::ScopedAStatus getVersionString(std::string* versionString) override;
+    ndk::ScopedAStatus prepareModel(
+            const Model& model, ExecutionPreference preference, Priority priority, int64_t deadline,
+            const std::vector<ndk::ScopedFileDescriptor>& modelCache,
+            const std::vector<ndk::ScopedFileDescriptor>& dataCache,
+            const std::vector<uint8_t>& token,
+            const std::shared_ptr<IPreparedModelCallback>& callback) override;
+    ndk::ScopedAStatus prepareModelFromCache(
+            int64_t deadline, const std::vector<ndk::ScopedFileDescriptor>& modelCache,
+            const std::vector<ndk::ScopedFileDescriptor>& dataCache,
+            const std::vector<uint8_t>& token,
+            const std::shared_ptr<IPreparedModelCallback>& callback) override;
+
+  private:
+    const Capabilities kCapabilities;
+    const NumberOfCacheFiles kNumberOfCacheFiles;
+    const std::vector<Extension> kExtensions;
+    const DeviceType kDeviceType;
+    const std::string kVersionString;
+};
+
+}  // namespace aidl::android::hardware::neuralnetworks
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/PreparedModel.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/PreparedModel.h
index 9b28588..abce6cc 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/PreparedModel.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/PreparedModel.h
@@ -22,7 +22,6 @@
 #include <nnapi/Result.h>
 #include <nnapi/Types.h>
 #include <nnapi/hal/CommonUtils.h>
-#include <nnapi/hal/aidl/ProtectCallback.h>
 
 #include <memory>
 #include <tuple>
@@ -35,8 +34,7 @@
 namespace aidl::android::hardware::neuralnetworks::utils {
 
 // Class that adapts aidl_hal::IPreparedModel to nn::IPreparedModel.
-class PreparedModel final : public nn::IPreparedModel,
-                            public std::enable_shared_from_this<PreparedModel> {
+class PreparedModel final : public nn::IPreparedModel {
     struct PrivateConstructorTag {};
 
   public:
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
index 58dcfe3..316d34f 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
@@ -21,6 +21,7 @@
 
 #include <android-base/logging.h>
 #include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
 #include <nnapi/Types.h>
 #include <nnapi/Validation.h>
 #include <nnapi/hal/HandleError.h>
@@ -48,6 +49,22 @@
     return result.has_value();
 }
 
+template <typename Type>
+nn::GeneralResult<void> compliantVersion(const Type& canonical) {
+    const auto version = NN_TRY(::android::hardware::neuralnetworks::utils::makeGeneralFailure(
+            nn::validate(canonical)));
+    if (version > kVersion) {
+        return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
+    }
+    return {};
+}
+
+template <typename Type>
+auto convertFromNonCanonical(const Type& nonCanonicalObject)
+        -> decltype(convert(nn::convert(nonCanonicalObject).value())) {
+    return convert(NN_TRY(nn::convert(nonCanonicalObject)));
+}
+
 nn::GeneralResult<Memory> clone(const Memory& memory);
 nn::GeneralResult<Request> clone(const Request& request);
 nn::GeneralResult<RequestMemoryPool> clone(const RequestMemoryPool& requestPool);
diff --git a/neuralnetworks/aidl/utils/src/Burst.cpp b/neuralnetworks/aidl/utils/src/Burst.cpp
new file mode 100644
index 0000000..0b475bc
--- /dev/null
+++ b/neuralnetworks/aidl/utils/src/Burst.cpp
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+
+#include "Burst.h"
+
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <nnapi/IBurst.h>
+#include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/HandleError.h>
+
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <utility>
+
+namespace aidl::android::hardware::neuralnetworks::utils {
+namespace {
+
+nn::GeneralResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> convertExecutionResults(
+        const std::vector<OutputShape>& outputShapes, const Timing& timing) {
+    return std::make_pair(NN_TRY(nn::convert(outputShapes)), NN_TRY(nn::convert(timing)));
+}
+
+}  // namespace
+
+Burst::MemoryCache::MemoryCache(std::shared_ptr<aidl_hal::IBurst> burst)
+    : kBurst(std::move(burst)) {}
+
+std::pair<int64_t, Burst::MemoryCache::SharedCleanup> Burst::MemoryCache::getOrCacheMemory(
+        const nn::SharedMemory& memory) {
+    std::lock_guard lock(mMutex);
+
+    // Get the cache payload or create it (with default values) if it does not exist.
+    auto& cachedPayload = mCache[memory];
+    {
+        const auto& [identifier, maybeCleaner] = cachedPayload;
+        // If cache payload already exists, reuse it.
+        if (auto cleaner = maybeCleaner.lock()) {
+            return std::make_pair(identifier, std::move(cleaner));
+        }
+    }
+
+    // If the code reaches this point, the cached payload either did not exist or expired prior to
+    // this call.
+
+    // Allocate a new identifier.
+    CHECK_LT(mUnusedIdentifier, std::numeric_limits<int64_t>::max());
+    const int64_t identifier = mUnusedIdentifier++;
+
+    // Create reference-counted self-cleaning cache object.
+    auto self = weak_from_this();
+    Task cleanup = [memory, identifier, maybeMemoryCache = std::move(self)] {
+        if (const auto memoryCache = maybeMemoryCache.lock()) {
+            memoryCache->tryFreeMemory(memory, identifier);
+        }
+    };
+    auto cleaner = std::make_shared<const Cleanup>(std::move(cleanup));
+
+    // Store the result in the cache and return it.
+    auto result = std::make_pair(identifier, std::move(cleaner));
+    cachedPayload = result;
+    return result;
+}
+
+std::optional<std::pair<int64_t, Burst::MemoryCache::SharedCleanup>>
+Burst::MemoryCache::getMemoryIfAvailable(const nn::SharedMemory& memory) {
+    std::lock_guard lock(mMutex);
+
+    // Get the existing cached entry if it exists.
+    const auto iter = mCache.find(memory);
+    if (iter != mCache.end()) {
+        const auto& [identifier, maybeCleaner] = iter->second;
+        if (auto cleaner = maybeCleaner.lock()) {
+            return std::make_pair(identifier, std::move(cleaner));
+        }
+    }
+
+    // If the code reaches this point, the cached payload did not exist or was actively being
+    // deleted.
+    return std::nullopt;
+}
+
+void Burst::MemoryCache::tryFreeMemory(const nn::SharedMemory& memory, int64_t identifier) {
+    {
+        std::lock_guard guard(mMutex);
+        // Remove the cached memory and payload if it is present but expired. Note that it may not
+        // be present or may not be expired because another thread may have removed or cached the
+        // same memory object before the current thread locked mMutex in tryFreeMemory.
+        const auto iter = mCache.find(memory);
+        if (iter != mCache.end()) {
+            if (std::get<WeakCleanup>(iter->second).expired()) {
+                mCache.erase(iter);
+            }
+        }
+    }
+    kBurst->releaseMemoryResource(identifier);
+}
+
+nn::GeneralResult<std::shared_ptr<const Burst>> Burst::create(
+        std::shared_ptr<aidl_hal::IBurst> burst) {
+    if (burst == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+               << "aidl_hal::utils::Burst::create must have non-null burst";
+    }
+
+    return std::make_shared<const Burst>(PrivateConstructorTag{}, std::move(burst));
+}
+
+Burst::Burst(PrivateConstructorTag /*tag*/, std::shared_ptr<aidl_hal::IBurst> burst)
+    : kBurst(std::move(burst)), kMemoryCache(std::make_shared<MemoryCache>(kBurst)) {
+    CHECK(kBurst != nullptr);
+}
+
+Burst::OptionalCacheHold Burst::cacheMemory(const nn::SharedMemory& memory) const {
+    auto [identifier, hold] = kMemoryCache->getOrCacheMemory(memory);
+    return hold;
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Burst::execute(
+        const nn::Request& request, nn::MeasureTiming measure,
+        const nn::OptionalTimePoint& deadline,
+        const nn::OptionalDuration& loopTimeoutDuration) const {
+    // Ensure that at most one execution is in flight at any given time.
+    const bool alreadyInFlight = mExecutionInFlight.test_and_set();
+    if (alreadyInFlight) {
+        return NN_ERROR() << "IBurst already has an execution in flight";
+    }
+    const auto guard = ::android::base::make_scope_guard([this] { mExecutionInFlight.clear(); });
+
+    // Ensure that request is ready for IPC.
+    std::optional<nn::Request> maybeRequestInShared;
+    const nn::Request& requestInShared = NN_TRY(hal::utils::makeExecutionFailure(
+            hal::utils::flushDataFromPointerToShared(&request, &maybeRequestInShared)));
+
+    const auto aidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
+    const auto aidlMeasure = NN_TRY(hal::utils::makeExecutionFailure(convert(measure)));
+    const auto aidlDeadline = NN_TRY(hal::utils::makeExecutionFailure(convert(deadline)));
+    const auto aidlLoopTimeoutDuration =
+            NN_TRY(hal::utils::makeExecutionFailure(convert(loopTimeoutDuration)));
+
+    std::vector<int64_t> memoryIdentifierTokens;
+    std::vector<OptionalCacheHold> holds;
+    memoryIdentifierTokens.reserve(request.pools.size());
+    holds.reserve(request.pools.size());
+    for (const auto& memoryPool : request.pools) {
+        if (const auto* memory = std::get_if<nn::SharedMemory>(&memoryPool)) {
+            if (auto cached = kMemoryCache->getMemoryIfAvailable(*memory)) {
+                auto& [identifier, hold] = *cached;
+                memoryIdentifierTokens.push_back(identifier);
+                holds.push_back(std::move(hold));
+                continue;
+            }
+        }
+        memoryIdentifierTokens.push_back(-1);
+    }
+    CHECK_EQ(request.pools.size(), memoryIdentifierTokens.size());
+
+    ExecutionResult executionResult;
+    const auto ret =
+            kBurst->executeSynchronously(aidlRequest, memoryIdentifierTokens, aidlMeasure,
+                                         aidlDeadline, aidlLoopTimeoutDuration, &executionResult);
+    HANDLE_ASTATUS(ret) << "execute failed";
+    if (!executionResult.outputSufficientSize) {
+        auto canonicalOutputShapes =
+                nn::convert(executionResult.outputShapes).value_or(std::vector<nn::OutputShape>{});
+        return NN_ERROR(nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, std::move(canonicalOutputShapes))
+               << "execution failed with " << nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
+    }
+    auto [outputShapes, timing] = NN_TRY(hal::utils::makeExecutionFailure(
+            convertExecutionResults(executionResult.outputShapes, executionResult.timing)));
+
+    NN_TRY(hal::utils::makeExecutionFailure(
+            hal::utils::unflushDataFromSharedToPointer(request, maybeRequestInShared)));
+
+    return std::make_pair(std::move(outputShapes), timing);
+}
+
+}  // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/utils/src/Conversions.cpp b/neuralnetworks/aidl/utils/src/Conversions.cpp
index c47ba0e..4b263ee 100644
--- a/neuralnetworks/aidl/utils/src/Conversions.cpp
+++ b/neuralnetworks/aidl/utils/src/Conversions.cpp
@@ -16,8 +16,13 @@
 
 #include "Conversions.h"
 
+#include <aidl/android/hardware/common/Ashmem.h>
+#include <aidl/android/hardware/common/MappableFile.h>
 #include <aidl/android/hardware/common/NativeHandle.h>
+#include <aidl/android/hardware/graphics/common/HardwareBuffer.h>
+#include <aidlcommonsupport/NativeHandle.h>
 #include <android-base/logging.h>
+#include <android-base/mapped_file.h>
 #include <android-base/unique_fd.h>
 #include <android/binder_auto_utils.h>
 #include <android/hardware_buffer.h>
@@ -41,6 +46,8 @@
 #include <type_traits>
 #include <utility>
 
+#include "Utils.h"
+
 #define VERIFY_NON_NEGATIVE(value) \
     while (UNLIKELY(value < 0)) return NN_ERROR()
 
@@ -53,7 +60,6 @@
     return static_cast<std::underlying_type_t<Type>>(value);
 }
 
-constexpr auto kVersion = android::nn::Version::ANDROID_S;
 constexpr int64_t kNoTiming = -1;
 
 }  // namespace
@@ -63,32 +69,6 @@
 
 using ::aidl::android::hardware::common::NativeHandle;
 
-constexpr auto validOperandType(nn::OperandType operandType) {
-    switch (operandType) {
-        case nn::OperandType::FLOAT32:
-        case nn::OperandType::INT32:
-        case nn::OperandType::UINT32:
-        case nn::OperandType::TENSOR_FLOAT32:
-        case nn::OperandType::TENSOR_INT32:
-        case nn::OperandType::TENSOR_QUANT8_ASYMM:
-        case nn::OperandType::BOOL:
-        case nn::OperandType::TENSOR_QUANT16_SYMM:
-        case nn::OperandType::TENSOR_FLOAT16:
-        case nn::OperandType::TENSOR_BOOL8:
-        case nn::OperandType::FLOAT16:
-        case nn::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
-        case nn::OperandType::TENSOR_QUANT16_ASYMM:
-        case nn::OperandType::TENSOR_QUANT8_SYMM:
-        case nn::OperandType::TENSOR_QUANT8_ASYMM_SIGNED:
-        case nn::OperandType::SUBGRAPH:
-            return true;
-        case nn::OperandType::OEM:
-        case nn::OperandType::TENSOR_OEM_BYTE:
-            return false;
-    }
-    return nn::isExtension(operandType);
-}
-
 template <typename Input>
 using UnvalidatedConvertOutput =
         std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
@@ -113,14 +93,7 @@
 template <typename Type>
 GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& halObject) {
     auto canonical = NN_TRY(nn::unvalidatedConvert(halObject));
-    const auto maybeVersion = validate(canonical);
-    if (!maybeVersion.has_value()) {
-        return error() << maybeVersion.error();
-    }
-    const auto version = maybeVersion.value();
-    if (version > kVersion) {
-        return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
-    }
+    NN_TRY(aidl_hal::utils::compliantVersion(canonical));
     return canonical;
 }
 
@@ -157,41 +130,38 @@
 
 using UniqueNativeHandle = std::unique_ptr<native_handle_t, NativeHandleDeleter>;
 
-static GeneralResult<UniqueNativeHandle> nativeHandleFromAidlHandle(const NativeHandle& handle) {
-    std::vector<base::unique_fd> fds;
-    fds.reserve(handle.fds.size());
-    for (const auto& fd : handle.fds) {
-        auto duplicatedFd = NN_TRY(dupFd(fd.get()));
-        fds.emplace_back(duplicatedFd.release());
+GeneralResult<UniqueNativeHandle> nativeHandleFromAidlHandle(const NativeHandle& handle) {
+    auto nativeHandle = UniqueNativeHandle(dupFromAidl(handle));
+    if (nativeHandle.get() == nullptr) {
+        return NN_ERROR() << "android::dupFromAidl failed to convert the common::NativeHandle to a "
+                             "native_handle_t";
     }
-
-    constexpr size_t kIntMax = std::numeric_limits<int>::max();
-    CHECK_LE(handle.fds.size(), kIntMax);
-    CHECK_LE(handle.ints.size(), kIntMax);
-    native_handle_t* nativeHandle = native_handle_create(static_cast<int>(handle.fds.size()),
-                                                         static_cast<int>(handle.ints.size()));
-    if (nativeHandle == nullptr) {
-        return NN_ERROR() << "Failed to create native_handle";
+    if (!std::all_of(nativeHandle->data + 0, nativeHandle->data + nativeHandle->numFds,
+                     [](int fd) { return fd >= 0; })) {
+        return NN_ERROR() << "android::dupFromAidl returned an invalid native_handle_t";
     }
-    for (size_t i = 0; i < fds.size(); ++i) {
-        nativeHandle->data[i] = fds[i].release();
-    }
-    std::copy(handle.ints.begin(), handle.ints.end(), &nativeHandle->data[nativeHandle->numFds]);
-
-    return UniqueNativeHandle(nativeHandle);
+    return nativeHandle;
 }
 
 }  // anonymous namespace
 
 GeneralResult<OperandType> unvalidatedConvert(const aidl_hal::OperandType& operandType) {
     VERIFY_NON_NEGATIVE(underlyingType(operandType)) << "Negative operand types are not allowed.";
-    return static_cast<OperandType>(operandType);
+    const auto canonical = static_cast<OperandType>(operandType);
+    if (canonical == OperandType::OEM || canonical == OperandType::TENSOR_OEM_BYTE) {
+        return NN_ERROR() << "Unable to convert invalid OperandType " << canonical;
+    }
+    return canonical;
 }
 
 GeneralResult<OperationType> unvalidatedConvert(const aidl_hal::OperationType& operationType) {
     VERIFY_NON_NEGATIVE(underlyingType(operationType))
             << "Negative operation types are not allowed.";
-    return static_cast<OperationType>(operationType);
+    const auto canonical = static_cast<OperationType>(operationType);
+    if (canonical == OperationType::OEM_OPERATION) {
+        return NN_ERROR() << "Unable to convert invalid OperationType OEM_OPERATION";
+    }
+    return canonical;
 }
 
 GeneralResult<DeviceType> unvalidatedConvert(const aidl_hal::DeviceType& deviceType) {
@@ -206,8 +176,7 @@
     const bool validOperandTypes = std::all_of(
             capabilities.operandPerformance.begin(), capabilities.operandPerformance.end(),
             [](const aidl_hal::OperandPerformance& operandPerformance) {
-                const auto maybeType = unvalidatedConvert(operandPerformance.type);
-                return !maybeType.has_value() ? false : validOperandType(maybeType.value());
+                return validatedConvert(operandPerformance.type).has_value();
             });
     if (!validOperandTypes) {
         return NN_ERROR() << "Invalid OperandType when unvalidatedConverting OperandPerformance in "
@@ -378,75 +347,74 @@
     return measureTiming ? MeasureTiming::YES : MeasureTiming::NO;
 }
 
-static uint32_t roundUpToMultiple(uint32_t value, uint32_t multiple) {
-    return (value + multiple - 1) / multiple * multiple;
-}
-
 GeneralResult<SharedMemory> unvalidatedConvert(const aidl_hal::Memory& memory) {
-    VERIFY_NON_NEGATIVE(memory.size) << "Memory size must not be negative";
-    if (memory.size > std::numeric_limits<size_t>::max()) {
-        return NN_ERROR() << "Memory: size must be <= std::numeric_limits<size_t>::max()";
-    }
+    using Tag = aidl_hal::Memory::Tag;
+    switch (memory.getTag()) {
+        case Tag::ashmem: {
+            const auto& ashmem = memory.get<Tag::ashmem>();
+            VERIFY_NON_NEGATIVE(ashmem.size) << "Memory size must not be negative";
+            if (ashmem.size > std::numeric_limits<size_t>::max()) {
+                return NN_ERROR() << "Memory: size must be <= std::numeric_limits<size_t>::max()";
+            }
 
-    if (memory.name != "hardware_buffer_blob") {
-        return std::make_shared<const Memory>(Memory{
-                .handle = NN_TRY(unvalidatedConvertHelper(memory.handle)),
-                .size = static_cast<size_t>(memory.size),
-                .name = memory.name,
-        });
-    }
+            auto handle = Memory::Ashmem{
+                    .fd = NN_TRY(dupFd(ashmem.fd.get())),
+                    .size = static_cast<size_t>(ashmem.size),
+            };
+            return std::make_shared<const Memory>(Memory{.handle = std::move(handle)});
+        }
+        case Tag::mappableFile: {
+            const auto& mappableFile = memory.get<Tag::mappableFile>();
+            VERIFY_NON_NEGATIVE(mappableFile.length) << "Memory size must not be negative";
+            VERIFY_NON_NEGATIVE(mappableFile.offset) << "Memory offset must not be negative";
+            if (mappableFile.length > std::numeric_limits<size_t>::max()) {
+                return NN_ERROR() << "Memory: size must be <= std::numeric_limits<size_t>::max()";
+            }
+            if (mappableFile.offset > std::numeric_limits<size_t>::max()) {
+                return NN_ERROR() << "Memory: offset must be <= std::numeric_limits<size_t>::max()";
+            }
 
-    const auto size = static_cast<uint32_t>(memory.size);
-    const auto format = AHARDWAREBUFFER_FORMAT_BLOB;
-    const auto usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
-    const uint32_t width = size;
-    const uint32_t height = 1;  // height is always 1 for BLOB mode AHardwareBuffer.
-    const uint32_t layers = 1;  // layers is always 1 for BLOB mode AHardwareBuffer.
+            const size_t size = static_cast<size_t>(mappableFile.length);
+            const int prot = mappableFile.prot;
+            const int fd = mappableFile.fd.get();
+            const size_t offset = static_cast<size_t>(mappableFile.offset);
 
-    const UniqueNativeHandle handle = NN_TRY(nativeHandleFromAidlHandle(memory.handle));
-    const native_handle_t* nativeHandle = handle.get();
+            return createSharedMemoryFromFd(size, prot, fd, offset);
+        }
+        case Tag::hardwareBuffer: {
+            const auto& hardwareBuffer = memory.get<Tag::hardwareBuffer>();
 
-    // AHardwareBuffer_createFromHandle() might fail because an allocator
-    // expects a specific stride value. In that case, we try to guess it by
-    // aligning the width to small powers of 2.
-    // TODO(b/174120849): Avoid stride assumptions.
-    AHardwareBuffer* hardwareBuffer = nullptr;
-    status_t status = UNKNOWN_ERROR;
-    for (uint32_t alignment : {1, 4, 32, 64, 128, 2, 8, 16}) {
-        const uint32_t stride = roundUpToMultiple(width, alignment);
-        AHardwareBuffer_Desc desc{
-                .width = width,
-                .height = height,
-                .layers = layers,
-                .format = format,
-                .usage = usage,
-                .stride = stride,
-        };
-        status = AHardwareBuffer_createFromHandle(&desc, nativeHandle,
-                                                  AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE,
-                                                  &hardwareBuffer);
-        if (status == NO_ERROR) {
-            break;
+            const UniqueNativeHandle handle =
+                    NN_TRY(nativeHandleFromAidlHandle(hardwareBuffer.handle));
+            const native_handle_t* nativeHandle = handle.get();
+
+            const AHardwareBuffer_Desc desc{
+                    .width = static_cast<uint32_t>(hardwareBuffer.description.width),
+                    .height = static_cast<uint32_t>(hardwareBuffer.description.height),
+                    .layers = static_cast<uint32_t>(hardwareBuffer.description.layers),
+                    .format = static_cast<uint32_t>(hardwareBuffer.description.format),
+                    .usage = static_cast<uint64_t>(hardwareBuffer.description.usage),
+                    .stride = static_cast<uint32_t>(hardwareBuffer.description.stride),
+            };
+            AHardwareBuffer* ahwb = nullptr;
+            const status_t status = AHardwareBuffer_createFromHandle(
+                    &desc, nativeHandle, AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, &ahwb);
+            if (status != NO_ERROR) {
+                return NN_ERROR() << "createFromHandle failed";
+            }
+
+            return createSharedMemoryFromAHWB(ahwb, /*takeOwnership=*/true);
         }
     }
-    if (status != NO_ERROR) {
-        return NN_ERROR(ErrorStatus::GENERAL_FAILURE)
-               << "Can't create AHardwareBuffer from handle. Error: " << status;
-    }
-
-    return std::make_shared<const Memory>(Memory{
-            .handle = HardwareBufferHandle(hardwareBuffer, /*takeOwnership=*/true),
-            .size = static_cast<size_t>(memory.size),
-            .name = memory.name,
-    });
+    return NN_ERROR() << "Unrecognized Memory::Tag: " << memory.getTag();
 }
 
 GeneralResult<Timing> unvalidatedConvert(const aidl_hal::Timing& timing) {
-    if (timing.timeInDriver < -1) {
-        return NN_ERROR() << "Timing: timeInDriver must not be less than -1";
+    if (timing.timeInDriverNs < -1) {
+        return NN_ERROR() << "Timing: timeInDriverNs must not be less than -1";
     }
-    if (timing.timeOnDevice < -1) {
-        return NN_ERROR() << "Timing: timeOnDevice must not be less than -1";
+    if (timing.timeOnDeviceNs < -1) {
+        return NN_ERROR() << "Timing: timeOnDeviceNs must not be less than -1";
     }
     constexpr auto convertTiming = [](int64_t halTiming) -> OptionalDuration {
         if (halTiming == kNoTiming) {
@@ -454,8 +422,8 @@
         }
         return nn::Duration(static_cast<uint64_t>(halTiming));
     };
-    return Timing{.timeOnDevice = convertTiming(timing.timeOnDevice),
-                  .timeInDriver = convertTiming(timing.timeInDriver)};
+    return Timing{.timeOnDevice = convertTiming(timing.timeOnDeviceNs),
+                  .timeInDriver = convertTiming(timing.timeInDriverNs)};
 }
 
 GeneralResult<Model::OperandValues> unvalidatedConvert(const std::vector<uint8_t>& operandValues) {
@@ -472,7 +440,7 @@
     return BufferRole{
             .modelIndex = static_cast<uint32_t>(bufferRole.modelIndex),
             .ioIndex = static_cast<uint32_t>(bufferRole.ioIndex),
-            .frequency = bufferRole.frequency,
+            .probability = bufferRole.probability,
     };
 }
 
@@ -534,6 +502,11 @@
     return std::make_shared<const Handle>(NN_TRY(unvalidatedConvertHelper(aidlNativeHandle)));
 }
 
+GeneralResult<std::vector<Operation>> unvalidatedConvert(
+        const std::vector<aidl_hal::Operation>& operations) {
+    return unvalidatedConvertVec(operations);
+}
+
 GeneralResult<SyncFence> unvalidatedConvert(const ndk::ScopedFileDescriptor& syncFence) {
     auto duplicatedFd = NN_TRY(dupFd(syncFence.get()));
     return SyncFence::create(std::move(duplicatedFd));
@@ -564,22 +537,14 @@
     return validatedConvert(model);
 }
 
-GeneralResult<Operand> convert(const aidl_hal::Operand& operand) {
-    return unvalidatedConvert(operand);
-}
-
 GeneralResult<OperandType> convert(const aidl_hal::OperandType& operandType) {
-    return unvalidatedConvert(operandType);
+    return validatedConvert(operandType);
 }
 
 GeneralResult<Priority> convert(const aidl_hal::Priority& priority) {
     return validatedConvert(priority);
 }
 
-GeneralResult<Request::MemoryPool> convert(const aidl_hal::RequestMemoryPool& memoryPool) {
-    return unvalidatedConvert(memoryPool);
-}
-
 GeneralResult<Request> convert(const aidl_hal::Request& request) {
     return validatedConvert(request);
 }
@@ -589,17 +554,13 @@
 }
 
 GeneralResult<SyncFence> convert(const ndk::ScopedFileDescriptor& syncFence) {
-    return unvalidatedConvert(syncFence);
+    return validatedConvert(syncFence);
 }
 
 GeneralResult<std::vector<Extension>> convert(const std::vector<aidl_hal::Extension>& extension) {
     return validatedConvert(extension);
 }
 
-GeneralResult<std::vector<Operation>> convert(const std::vector<aidl_hal::Operation>& operations) {
-    return unvalidatedConvert(operations);
-}
-
 GeneralResult<std::vector<SharedMemory>> convert(const std::vector<aidl_hal::Memory>& memories) {
     return validatedConvert(memories);
 }
@@ -644,14 +605,7 @@
 
 template <typename Type>
 nn::GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& canonical) {
-    const auto maybeVersion = nn::validate(canonical);
-    if (!maybeVersion.has_value()) {
-        return nn::error() << maybeVersion.error();
-    }
-    const auto version = maybeVersion.value();
-    if (version > kVersion) {
-        return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
-    }
+    NN_TRY(compliantVersion(canonical));
     return utils::unvalidatedConvert(canonical);
 }
 
@@ -684,20 +638,95 @@
 template <class... Ts>
 overloaded(Ts...)->overloaded<Ts...>;
 
-static nn::GeneralResult<common::NativeHandle> aidlHandleFromNativeHandle(
-        const native_handle_t& handle) {
-    common::NativeHandle aidlNativeHandle;
+nn::GeneralResult<common::NativeHandle> aidlHandleFromNativeHandle(
+        const native_handle_t& nativeHandle) {
+    auto handle = ::android::dupToAidl(&nativeHandle);
+    if (!std::all_of(handle.fds.begin(), handle.fds.end(),
+                     [](const ndk::ScopedFileDescriptor& fd) { return fd.get() >= 0; })) {
+        return NN_ERROR() << "android::dupToAidl returned an invalid common::NativeHandle";
+    }
+    return handle;
+}
 
-    aidlNativeHandle.fds.reserve(handle.numFds);
-    for (int i = 0; i < handle.numFds; ++i) {
-        auto duplicatedFd = NN_TRY(nn::dupFd(handle.data[i]));
-        aidlNativeHandle.fds.emplace_back(duplicatedFd.release());
+nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::Ashmem& memory) {
+    if constexpr (std::numeric_limits<size_t>::max() > std::numeric_limits<int64_t>::max()) {
+        if (memory.size > std::numeric_limits<int64_t>::max()) {
+            return (
+                           NN_ERROR()
+                           << "Memory::Ashmem: size must be <= std::numeric_limits<int64_t>::max()")
+                    .
+                    operator nn::GeneralResult<Memory>();
+        }
     }
 
-    aidlNativeHandle.ints = std::vector<int>(&handle.data[handle.numFds],
-                                             &handle.data[handle.numFds + handle.numInts]);
+    auto fd = NN_TRY(nn::dupFd(memory.fd));
+    auto handle = common::Ashmem{
+            .fd = ndk::ScopedFileDescriptor(fd.release()),
+            .size = static_cast<int64_t>(memory.size),
+    };
+    return Memory::make<Memory::Tag::ashmem>(std::move(handle));
+}
 
-    return aidlNativeHandle;
+nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::Fd& memory) {
+    if constexpr (std::numeric_limits<size_t>::max() > std::numeric_limits<int64_t>::max()) {
+        if (memory.size > std::numeric_limits<int64_t>::max()) {
+            return (NN_ERROR() << "Memory::Fd: size must be <= std::numeric_limits<int64_t>::max()")
+                    .
+                    operator nn::GeneralResult<Memory>();
+        }
+        if (memory.offset > std::numeric_limits<int64_t>::max()) {
+            return (
+                           NN_ERROR()
+                           << "Memory::Fd: offset must be <= std::numeric_limits<int64_t>::max()")
+                    .
+                    operator nn::GeneralResult<Memory>();
+        }
+    }
+
+    auto fd = NN_TRY(nn::dupFd(memory.fd));
+    auto handle = common::MappableFile{
+            .length = static_cast<int64_t>(memory.size),
+            .prot = memory.prot,
+            .fd = ndk::ScopedFileDescriptor(fd.release()),
+            .offset = static_cast<int64_t>(memory.offset),
+    };
+    return Memory::make<Memory::Tag::mappableFile>(std::move(handle));
+}
+
+nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::HardwareBuffer& memory) {
+    const native_handle_t* nativeHandle = AHardwareBuffer_getNativeHandle(memory.handle.get());
+    if (nativeHandle == nullptr) {
+        return (NN_ERROR() << "unvalidatedConvert failed because AHardwareBuffer_getNativeHandle "
+                              "returned nullptr")
+                .
+                operator nn::GeneralResult<Memory>();
+    }
+
+    auto handle = NN_TRY(aidlHandleFromNativeHandle(*nativeHandle));
+
+    AHardwareBuffer_Desc desc;
+    AHardwareBuffer_describe(memory.handle.get(), &desc);
+
+    const auto description = graphics::common::HardwareBufferDescription{
+            .width = static_cast<int32_t>(desc.width),
+            .height = static_cast<int32_t>(desc.height),
+            .layers = static_cast<int32_t>(desc.layers),
+            .format = static_cast<graphics::common::PixelFormat>(desc.format),
+            .usage = static_cast<graphics::common::BufferUsage>(desc.usage),
+            .stride = static_cast<int32_t>(desc.stride),
+    };
+
+    auto hardwareBuffer = graphics::common::HardwareBuffer{
+            .description = std::move(description),
+            .handle = std::move(handle),
+    };
+    return Memory::make<Memory::Tag::hardwareBuffer>(std::move(hardwareBuffer));
+}
+
+nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::Unknown& /*memory*/) {
+    return (NN_ERROR() << "Unable to convert Unknown memory type")
+            .
+            operator nn::GeneralResult<Memory>();
 }
 
 }  // namespace
@@ -718,7 +747,7 @@
     return BufferRole{
             .modelIndex = static_cast<int32_t>(bufferRole.modelIndex),
             .ioIndex = static_cast<int32_t>(bufferRole.ioIndex),
-            .frequency = bufferRole.frequency,
+            .probability = bufferRole.probability,
     };
 }
 
@@ -732,41 +761,12 @@
 }
 
 nn::GeneralResult<Memory> unvalidatedConvert(const nn::SharedMemory& memory) {
-    CHECK(memory != nullptr);
-    if (memory->size > std::numeric_limits<int64_t>::max()) {
-        return NN_ERROR() << "Memory size doesn't fit into int64_t.";
+    if (memory == nullptr) {
+        return (NN_ERROR() << "Unable to convert nullptr memory")
+                .
+                operator nn::GeneralResult<Memory>();
     }
-    if (const auto* handle = std::get_if<nn::Handle>(&memory->handle)) {
-        return Memory{
-                .handle = NN_TRY(unvalidatedConvert(*handle)),
-                .size = static_cast<int64_t>(memory->size),
-                .name = memory->name,
-        };
-    }
-
-    const auto* ahwb = std::get<nn::HardwareBufferHandle>(memory->handle).get();
-    AHardwareBuffer_Desc bufferDesc;
-    AHardwareBuffer_describe(ahwb, &bufferDesc);
-
-    if (bufferDesc.format == AHARDWAREBUFFER_FORMAT_BLOB) {
-        CHECK_EQ(memory->size, bufferDesc.width);
-        CHECK_EQ(memory->name, "hardware_buffer_blob");
-    } else {
-        CHECK_EQ(memory->size, 0u);
-        CHECK_EQ(memory->name, "hardware_buffer");
-    }
-
-    const native_handle_t* nativeHandle = AHardwareBuffer_getNativeHandle(ahwb);
-    if (nativeHandle == nullptr) {
-        return NN_ERROR() << "unvalidatedConvert failed because AHardwareBuffer_getNativeHandle "
-                             "returned nullptr";
-    }
-
-    return Memory{
-            .handle = NN_TRY(aidlHandleFromNativeHandle(*nativeHandle)),
-            .size = static_cast<int64_t>(memory->size),
-            .name = memory->name,
-    };
+    return std::visit([](const auto& x) { return unvalidatedConvert(x); }, memory->handle);
 }
 
 nn::GeneralResult<ErrorStatus> unvalidatedConvert(const nn::ErrorStatus& errorStatus) {
@@ -797,6 +797,9 @@
 }
 
 nn::GeneralResult<OperandType> unvalidatedConvert(const nn::OperandType& operandType) {
+    if (operandType == nn::OperandType::OEM || operandType == nn::OperandType::TENSOR_OEM_BYTE) {
+        return NN_ERROR() << "Unable to convert invalid OperandType " << operandType;
+    }
     return static_cast<OperandType>(operandType);
 }
 
@@ -864,6 +867,9 @@
 }
 
 nn::GeneralResult<OperationType> unvalidatedConvert(const nn::OperationType& operationType) {
+    if (operationType == nn::OperationType::OEM_OPERATION) {
+        return NN_ERROR() << "Unable to convert invalid OperationType OEM_OPERATION";
+    }
     return static_cast<OperationType>(operationType);
 }
 
@@ -958,17 +964,18 @@
 
 nn::GeneralResult<Timing> unvalidatedConvert(const nn::Timing& timing) {
     return Timing{
-            .timeOnDevice = NN_TRY(unvalidatedConvert(timing.timeOnDevice)),
-            .timeInDriver = NN_TRY(unvalidatedConvert(timing.timeInDriver)),
+            .timeOnDeviceNs = NN_TRY(unvalidatedConvert(timing.timeOnDevice)),
+            .timeInDriverNs = NN_TRY(unvalidatedConvert(timing.timeInDriver)),
     };
 }
 
 nn::GeneralResult<int64_t> unvalidatedConvert(const nn::Duration& duration) {
-    const uint64_t nanoseconds = duration.count();
-    if (nanoseconds > std::numeric_limits<int64_t>::max()) {
-        return std::numeric_limits<int64_t>::max();
+    if (duration < nn::Duration::zero()) {
+        return NN_ERROR() << "Unable to convert invalid (negative) duration";
     }
-    return static_cast<int64_t>(nanoseconds);
+    constexpr std::chrono::nanoseconds::rep kIntMax = std::numeric_limits<int64_t>::max();
+    const auto count = duration.count();
+    return static_cast<int64_t>(std::min(count, kIntMax));
 }
 
 nn::GeneralResult<int64_t> unvalidatedConvert(const nn::OptionalDuration& optionalDuration) {
@@ -1004,7 +1011,7 @@
 }
 
 nn::GeneralResult<std::vector<uint8_t>> convert(const nn::CacheToken& cacheToken) {
-    return unvalidatedConvert(cacheToken);
+    return validatedConvert(cacheToken);
 }
 
 nn::GeneralResult<BufferDesc> convert(const nn::BufferDesc& bufferDesc) {
@@ -1076,7 +1083,7 @@
 
 nn::GeneralResult<std::vector<ndk::ScopedFileDescriptor>> convert(
         const std::vector<nn::SyncFence>& syncFences) {
-    return unvalidatedConvert(syncFences);
+    return validatedConvert(syncFences);
 }
 
 nn::GeneralResult<std::vector<int32_t>> toSigned(const std::vector<uint32_t>& vec) {
diff --git a/neuralnetworks/aidl/utils/src/InvalidDevice.cpp b/neuralnetworks/aidl/utils/src/InvalidDevice.cpp
new file mode 100644
index 0000000..c9d9955
--- /dev/null
+++ b/neuralnetworks/aidl/utils/src/InvalidDevice.cpp
@@ -0,0 +1,179 @@
+/*
+ * 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 "InvalidDevice"
+
+#include "InvalidDevice.h"
+
+#include <aidl/android/hardware/neuralnetworks/BnBuffer.h>
+#include <aidl/android/hardware/neuralnetworks/BnDevice.h>
+#include <aidl/android/hardware/neuralnetworks/BnPreparedModel.h>
+#include <android/binder_auto_utils.h>
+
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace aidl::android::hardware::neuralnetworks {
+namespace {
+
+ndk::ScopedAStatus toAStatus(ErrorStatus errorStatus, const std::string& errorMessage) {
+    if (errorStatus == ErrorStatus::NONE) {
+        return ndk::ScopedAStatus::ok();
+    }
+    return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+            static_cast<int32_t>(errorStatus), errorMessage.c_str());
+}
+
+}  // namespace
+
+std::shared_ptr<InvalidDevice> InvalidDevice::create() {
+    constexpr auto perf = PerformanceInfo{
+            .execTime = std::numeric_limits<float>::max(),
+            .powerUsage = std::numeric_limits<float>::max(),
+    };
+    auto capabilities = Capabilities{
+            .relaxedFloat32toFloat16PerformanceScalar = perf,
+            .relaxedFloat32toFloat16PerformanceTensor = perf,
+            .operandPerformance = {},
+            .ifPerformance = perf,
+            .whilePerformance = perf,
+    };
+    constexpr auto numberOfCacheFiles = NumberOfCacheFiles{
+            .numModelCache = 0,
+            .numDataCache = 0,
+    };
+    std::vector<Extension> extensions{};
+    constexpr auto deviceType = DeviceType::OTHER;
+    std::string versionString = "invalid";
+
+    return ndk::SharedRefBase::make<InvalidDevice>(std::move(capabilities), numberOfCacheFiles,
+                                                   std::move(extensions), deviceType,
+                                                   std::move(versionString));
+}
+
+InvalidDevice::InvalidDevice(Capabilities capabilities,
+                             const NumberOfCacheFiles& numberOfCacheFiles,
+                             std::vector<Extension> extensions, DeviceType deviceType,
+                             std::string versionString)
+    : kCapabilities(std::move(capabilities)),
+      kNumberOfCacheFiles(numberOfCacheFiles),
+      kExtensions(std::move(extensions)),
+      kDeviceType(deviceType),
+      kVersionString(std::move(versionString)) {}
+
+ndk::ScopedAStatus InvalidDevice::allocate(
+        const BufferDesc& /*desc*/, const std::vector<IPreparedModelParcel>& /*preparedModels*/,
+        const std::vector<BufferRole>& /*inputRoles*/,
+        const std::vector<BufferRole>& /*outputRoles*/, DeviceBuffer* /*deviceBuffer*/) {
+    return toAStatus(ErrorStatus::GENERAL_FAILURE, "InvalidDevice");
+}
+
+ndk::ScopedAStatus InvalidDevice::getCapabilities(Capabilities* capabilities) {
+    *capabilities = kCapabilities;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::getNumberOfCacheFilesNeeded(
+        NumberOfCacheFiles* numberOfCacheFiles) {
+    *numberOfCacheFiles = kNumberOfCacheFiles;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::getSupportedExtensions(std::vector<Extension>* extensions) {
+    *extensions = kExtensions;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::getSupportedOperations(const Model& model,
+                                                         std::vector<bool>* supportedOperations) {
+    if (const auto result = utils::validate(model); !result.ok()) {
+        return toAStatus(ErrorStatus::INVALID_ARGUMENT, result.error());
+    }
+    *supportedOperations = std::vector<bool>(model.main.operations.size(), false);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::getType(DeviceType* deviceType) {
+    *deviceType = kDeviceType;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::getVersionString(std::string* versionString) {
+    *versionString = kVersionString;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::prepareModel(
+        const Model& model, ExecutionPreference preference, Priority priority, int64_t deadline,
+        const std::vector<ndk::ScopedFileDescriptor>& modelCache,
+        const std::vector<ndk::ScopedFileDescriptor>& dataCache, const std::vector<uint8_t>& token,
+        const std::shared_ptr<IPreparedModelCallback>& callback) {
+    if (callback.get() == nullptr) {
+        return toAStatus(ErrorStatus::INVALID_ARGUMENT,
+                         "invalid callback passed to InvalidDevice::prepareModel");
+    }
+    if (const auto result = utils::validate(model); !result.ok()) {
+        callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+        return toAStatus(ErrorStatus::INVALID_ARGUMENT, result.error());
+    }
+    if (const auto result = utils::validate(preference); !result.ok()) {
+        callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+        return toAStatus(ErrorStatus::INVALID_ARGUMENT, result.error());
+    }
+    if (const auto result = utils::validate(priority); !result.ok()) {
+        callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+        return toAStatus(ErrorStatus::INVALID_ARGUMENT, result.error());
+    }
+    if (deadline < -1) {
+        callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+        return toAStatus(ErrorStatus::INVALID_ARGUMENT,
+                         "Invalid deadline " + std::to_string(deadline));
+    }
+    if (modelCache.size() != static_cast<size_t>(kNumberOfCacheFiles.numModelCache)) {
+        callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+        return toAStatus(ErrorStatus::INVALID_ARGUMENT,
+                         "Invalid modelCache, size = " + std::to_string(modelCache.size()));
+    }
+    if (dataCache.size() != static_cast<size_t>(kNumberOfCacheFiles.numDataCache)) {
+        callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+        return toAStatus(ErrorStatus::INVALID_ARGUMENT,
+                         "Invalid modelCache, size = " + std::to_string(dataCache.size()));
+    }
+    if (token.size() != IDevice::BYTE_SIZE_OF_CACHE_TOKEN) {
+        callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+        return toAStatus(
+                ErrorStatus::INVALID_ARGUMENT,
+                "Invalid cache token, size = " + std::to_string(IDevice::BYTE_SIZE_OF_CACHE_TOKEN));
+    }
+    callback->notify(ErrorStatus::GENERAL_FAILURE, nullptr);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::prepareModelFromCache(
+        int64_t /*deadline*/, const std::vector<ndk::ScopedFileDescriptor>& /*modelCache*/,
+        const std::vector<ndk::ScopedFileDescriptor>& /*dataCache*/,
+        const std::vector<uint8_t>& /*token*/,
+        const std::shared_ptr<IPreparedModelCallback>& callback) {
+    callback->notify(ErrorStatus::GENERAL_FAILURE, nullptr);
+    return toAStatus(ErrorStatus::GENERAL_FAILURE, "InvalidDevice");
+}
+
+}  // namespace aidl::android::hardware::neuralnetworks
diff --git a/neuralnetworks/aidl/utils/src/PreparedModel.cpp b/neuralnetworks/aidl/utils/src/PreparedModel.cpp
index aee4d90..003965b 100644
--- a/neuralnetworks/aidl/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/aidl/utils/src/PreparedModel.cpp
@@ -16,9 +16,9 @@
 
 #include "PreparedModel.h"
 
+#include "Burst.h"
 #include "Callbacks.h"
 #include "Conversions.h"
-#include "ProtectCallback.h"
 #include "Utils.h"
 
 #include <android/binder_auto_utils.h>
@@ -26,7 +26,6 @@
 #include <nnapi/Result.h>
 #include <nnapi/TypeUtils.h>
 #include <nnapi/Types.h>
-#include <nnapi/hal/1.0/Burst.h>
 #include <nnapi/hal/CommonUtils.h>
 #include <nnapi/hal/HandleError.h>
 
@@ -161,7 +160,10 @@
 }
 
 nn::GeneralResult<nn::SharedBurst> PreparedModel::configureExecutionBurst() const {
-    return hal::V1_0::utils::Burst::create(shared_from_this());
+    std::shared_ptr<IBurst> burst;
+    const auto ret = kPreparedModel->configureExecutionBurst(&burst);
+    HANDLE_ASTATUS(ret) << "configureExecutionBurst failed";
+    return Burst::create(std::move(burst));
 }
 
 std::any PreparedModel::getUnderlyingResource() const {
diff --git a/neuralnetworks/aidl/utils/src/Service.cpp b/neuralnetworks/aidl/utils/src/Service.cpp
index 511de55..ac182a2 100644
--- a/neuralnetworks/aidl/utils/src/Service.cpp
+++ b/neuralnetworks/aidl/utils/src/Service.cpp
@@ -16,6 +16,7 @@
 
 #include "Service.h"
 
+#include <AndroidVersionUtil.h>
 #include <android/binder_auto_utils.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
@@ -35,13 +36,23 @@
     hal::utils::ResilientDevice::Factory makeDevice =
             [instanceName,
              name = std::move(fullName)](bool blocking) -> nn::GeneralResult<nn::SharedDevice> {
-        const auto& getService =
-                blocking ? AServiceManager_getService : AServiceManager_checkService;
+        std::add_pointer_t<AIBinder*(const char*)> getService;
+        if (blocking) {
+            if (__builtin_available(android __NNAPI_AIDL_MIN_ANDROID_API__, *)) {
+                getService = AServiceManager_waitForService;
+            } else {
+                getService = AServiceManager_getService;
+            }
+        } else {
+            getService = AServiceManager_checkService;
+        }
+
         auto service = IDevice::fromBinder(ndk::SpAIBinder(getService(name.c_str())));
         if (service == nullptr) {
-            return NN_ERROR() << (blocking ? "AServiceManager_getService"
-                                           : "AServiceManager_checkService")
-                              << " returned nullptr";
+            return NN_ERROR()
+                   << (blocking ? "AServiceManager_waitForService (or AServiceManager_getService)"
+                                : "AServiceManager_checkService")
+                   << " returned nullptr";
         }
         ABinderProcess_startThreadPool();
         return Device::create(instanceName, std::move(service));
diff --git a/neuralnetworks/aidl/utils/src/Utils.cpp b/neuralnetworks/aidl/utils/src/Utils.cpp
index 95516c8..03407be 100644
--- a/neuralnetworks/aidl/utils/src/Utils.cpp
+++ b/neuralnetworks/aidl/utils/src/Utils.cpp
@@ -16,12 +16,20 @@
 
 #include "Utils.h"
 
+#include <aidl/android/hardware/common/Ashmem.h>
+#include <aidl/android/hardware/common/MappableFile.h>
+#include <aidl/android/hardware/graphics/common/HardwareBuffer.h>
+#include <android/binder_auto_utils.h>
 #include <android/binder_status.h>
 #include <nnapi/Result.h>
+#include <nnapi/SharedMemory.h>
 
 namespace aidl::android::hardware::neuralnetworks::utils {
 namespace {
 
+nn::GeneralResult<ndk::ScopedFileDescriptor> clone(const ndk::ScopedFileDescriptor& fd);
+using utils::clone;
+
 template <typename Type>
 nn::GeneralResult<std::vector<Type>> cloneVec(const std::vector<Type>& arguments) {
     std::vector<Type> clonedObjects;
@@ -37,24 +45,52 @@
     return cloneVec(arguments);
 }
 
+nn::GeneralResult<ndk::ScopedFileDescriptor> clone(const ndk::ScopedFileDescriptor& fd) {
+    auto duplicatedFd = NN_TRY(nn::dupFd(fd.get()));
+    return ndk::ScopedFileDescriptor(duplicatedFd.release());
+}
+
+nn::GeneralResult<common::NativeHandle> clone(const common::NativeHandle& handle) {
+    return common::NativeHandle{
+            .fds = NN_TRY(cloneVec(handle.fds)),
+            .ints = handle.ints,
+    };
+}
+
 }  // namespace
 
 nn::GeneralResult<Memory> clone(const Memory& memory) {
-    common::NativeHandle nativeHandle;
-    nativeHandle.ints = memory.handle.ints;
-    nativeHandle.fds.reserve(memory.handle.fds.size());
-    for (const auto& fd : memory.handle.fds) {
-        const int newFd = dup(fd.get());
-        if (newFd < 0) {
-            return NN_ERROR() << "Couldn't dup a file descriptor";
+    switch (memory.getTag()) {
+        case Memory::Tag::ashmem: {
+            const auto& ashmem = memory.get<Memory::Tag::ashmem>();
+            auto handle = common::Ashmem{
+                    .fd = NN_TRY(clone(ashmem.fd)),
+                    .size = ashmem.size,
+            };
+            return Memory::make<Memory::Tag::ashmem>(std::move(handle));
         }
-        nativeHandle.fds.emplace_back(newFd);
+        case Memory::Tag::mappableFile: {
+            const auto& memFd = memory.get<Memory::Tag::mappableFile>();
+            auto handle = common::MappableFile{
+                    .length = memFd.length,
+                    .prot = memFd.prot,
+                    .fd = NN_TRY(clone(memFd.fd)),
+                    .offset = memFd.offset,
+            };
+            return Memory::make<Memory::Tag::mappableFile>(std::move(handle));
+        }
+        case Memory::Tag::hardwareBuffer: {
+            const auto& hardwareBuffer = memory.get<Memory::Tag::hardwareBuffer>();
+            auto handle = graphics::common::HardwareBuffer{
+                    .description = hardwareBuffer.description,
+                    .handle = NN_TRY(clone(hardwareBuffer.handle)),
+            };
+            return Memory::make<Memory::Tag::hardwareBuffer>(std::move(handle));
+        }
     }
-    return Memory{
-            .handle = std::move(nativeHandle),
-            .size = memory.size,
-            .name = memory.name,
-    };
+    return (NN_ERROR() << "Unrecognized Memory::Tag: " << memory.getTag())
+            .
+            operator nn::GeneralResult<Memory>();
 }
 
 nn::GeneralResult<RequestMemoryPool> clone(const RequestMemoryPool& requestPool) {
diff --git a/neuralnetworks/aidl/utils/test/MockBuffer.h b/neuralnetworks/aidl/utils/test/MockBuffer.h
index 5746176..f77fa86 100644
--- a/neuralnetworks/aidl/utils/test/MockBuffer.h
+++ b/neuralnetworks/aidl/utils/test/MockBuffer.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_BUFFER
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_BUFFER
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_BUFFER_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_BUFFER_H
 
 #include <aidl/android/hardware/neuralnetworks/BnBuffer.h>
 #include <android/binder_interface_utils.h>
@@ -40,4 +40,4 @@
 
 }  // namespace aidl::android::hardware::neuralnetworks::utils
 
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_BUFFER
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_BUFFER_H
diff --git a/neuralnetworks/aidl/utils/test/MockBurst.h b/neuralnetworks/aidl/utils/test/MockBurst.h
new file mode 100644
index 0000000..5083bbd
--- /dev/null
+++ b/neuralnetworks/aidl/utils/test/MockBurst.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_BURST_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_BURST_H
+
+#include <aidl/android/hardware/neuralnetworks/BnBurst.h>
+#include <android/binder_interface_utils.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hidl/Status.h>
+
+namespace aidl::android::hardware::neuralnetworks::utils {
+
+class MockBurst final : public BnBurst {
+  public:
+    MOCK_METHOD(ndk::ScopedAStatus, executeSynchronously,
+                (const Request& request, const std::vector<int64_t>& memoryIdentifierTokens,
+                 bool measureTiming, int64_t deadline, int64_t loopTimeoutDuration,
+                 ExecutionResult* executionResult),
+                (override));
+    MOCK_METHOD(ndk::ScopedAStatus, releaseMemoryResource, (int64_t memoryIdentifierToken),
+                (override));
+};
+
+}  // namespace aidl::android::hardware::neuralnetworks::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_BURST_H
diff --git a/neuralnetworks/aidl/utils/test/MockDevice.h b/neuralnetworks/aidl/utils/test/MockDevice.h
index 9b35bf8..3a28d55 100644
--- a/neuralnetworks/aidl/utils/test/MockDevice.h
+++ b/neuralnetworks/aidl/utils/test/MockDevice.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_DEVICE
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_DEVICE
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_DEVICE_H
 
 #include <aidl/android/hardware/neuralnetworks/BnDevice.h>
 #include <android/binder_auto_utils.h>
@@ -64,4 +64,4 @@
 
 }  // namespace aidl::android::hardware::neuralnetworks::utils
 
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_DEVICE
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_DEVICE_H
diff --git a/neuralnetworks/aidl/utils/test/MockFencedExecutionCallback.h b/neuralnetworks/aidl/utils/test/MockFencedExecutionCallback.h
index 463e1c9..06f9ea2 100644
--- a/neuralnetworks/aidl/utils/test/MockFencedExecutionCallback.h
+++ b/neuralnetworks/aidl/utils/test/MockFencedExecutionCallback.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_FENCED_EXECUTION_CALLBACK
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_FENCED_EXECUTION_CALLBACK
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_FENCED_EXECUTION_CALLBACK_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_FENCED_EXECUTION_CALLBACK_H
 
 #include <aidl/android/hardware/neuralnetworks/BnFencedExecutionCallback.h>
 #include <android/binder_auto_utils.h>
@@ -42,4 +42,4 @@
 
 }  // namespace aidl::android::hardware::neuralnetworks::utils
 
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_FENCED_EXECUTION_CALLBACK
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_FENCED_EXECUTION_CALLBACK_H
diff --git a/neuralnetworks/aidl/utils/test/MockPreparedModel.h b/neuralnetworks/aidl/utils/test/MockPreparedModel.h
index 36e0ec3..a4ae2b7 100644
--- a/neuralnetworks/aidl/utils/test/MockPreparedModel.h
+++ b/neuralnetworks/aidl/utils/test/MockPreparedModel.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_PREPARED_MODEL
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_PREPARED_MODEL
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_PREPARED_MODEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_PREPARED_MODEL_H
 
 #include <aidl/android/hardware/neuralnetworks/BnPreparedModel.h>
 #include <android/binder_interface_utils.h>
@@ -49,4 +49,4 @@
 
 }  // namespace aidl::android::hardware::neuralnetworks::utils
 
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_PREPARED_MODEL
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_AIDL_UTILS_TEST_MOCK_PREPARED_MODEL_H
diff --git a/neuralnetworks/aidl/utils/test/PreparedModelTest.cpp b/neuralnetworks/aidl/utils/test/PreparedModelTest.cpp
index 7e28861..ff98a7d 100644
--- a/neuralnetworks/aidl/utils/test/PreparedModelTest.cpp
+++ b/neuralnetworks/aidl/utils/test/PreparedModelTest.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "MockBurst.h"
 #include "MockFencedExecutionCallback.h"
 #include "MockPreparedModel.h"
 
@@ -38,7 +39,7 @@
 using ::testing::SetArgPointee;
 
 const std::shared_ptr<IPreparedModel> kInvalidPreparedModel;
-constexpr auto kNoTiming = Timing{.timeOnDevice = -1, .timeInDriver = -1};
+constexpr auto kNoTiming = Timing{.timeOnDeviceNs = -1, .timeInDriverNs = -1};
 
 constexpr auto makeStatusOk = [] { return ndk::ScopedAStatus::ok(); };
 
@@ -252,7 +253,71 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-// TODO: test burst execution if/when it is added to nn::IPreparedModel.
+TEST(PreparedModelTest, configureExecutionBurst) {
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    const auto mockBurst = ndk::SharedRefBase::make<MockBurst>();
+    EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_))
+            .Times(1)
+            .WillOnce(DoAll(SetArgPointee<0>(mockBurst), Invoke(makeStatusOk)));
+    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+
+    // run test
+    const auto result = preparedModel->configureExecutionBurst();
+
+    // verify result
+    ASSERT_TRUE(result.has_value())
+            << "Failed with " << result.error().code << ": " << result.error().message;
+    EXPECT_NE(result.value(), nullptr);
+}
+
+TEST(PreparedModelTest, configureExecutionBurstError) {
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeGeneralFailure));
+    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+
+    // run test
+    const auto result = preparedModel->configureExecutionBurst();
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(PreparedModelTest, configureExecutionBurstTransportFailure) {
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
+    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+
+    // run test
+    const auto result = preparedModel->configureExecutionBurst();
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST(PreparedModelTest, configureExecutionBurstDeadObject) {
+    // setup test
+    const auto mockPreparedModel = MockPreparedModel::create();
+    EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_))
+            .Times(1)
+            .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
+    const auto preparedModel = PreparedModel::create(mockPreparedModel).value();
+
+    // run test
+    const auto result = preparedModel->configureExecutionBurst();
+
+    // verify result
+    ASSERT_FALSE(result.has_value());
+    EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
+}
 
 TEST(PreparedModelTest, getUnderlyingResource) {
     // setup test
diff --git a/neuralnetworks/aidl/vts/functional/Android.bp b/neuralnetworks/aidl/vts/functional/Android.bp
index 7804c2a..d5b150a 100644
--- a/neuralnetworks/aidl/vts/functional/Android.bp
+++ b/neuralnetworks/aidl/vts/functional/Android.bp
@@ -50,9 +50,11 @@
     ],
     static_libs: [
         "android.hardware.common-V2-ndk_platform",
+        "android.hardware.graphics.common-V2-ndk_platform",
         "android.hardware.neuralnetworks-V1-ndk_platform",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
+        "libaidlcommonsupport",
         "libgmock",
         "libhidlmemory",
         "libneuralnetworks_generated_test_harness",
diff --git a/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
index 2dd02dd..d3b041d 100644
--- a/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
@@ -102,7 +102,7 @@
         ASSERT_NE(result, nullptr);
 
         // Prepare arguments.
-        BufferRole role = {.modelIndex = 0, .ioIndex = index, .frequency = 1.0f};
+        BufferRole role = {.modelIndex = 0, .ioIndex = index, .probability = 1.0f};
         std::vector<BufferRole> inputRoles, outputRoles;
         if constexpr (ioType == IOType::INPUT) {
             inputRoles = {role};
@@ -547,7 +547,7 @@
         makeOutputInsufficientSize(kInsufficientOutputIndex, &request);
     }
 
-    int64_t loopTimeoutDuration = kOmittedTimeoutDuration;
+    int64_t loopTimeoutDurationNs = kOmittedTimeoutDuration;
     // OutputType::MISSED_DEADLINE is only used by
     // TestKind::INTINITE_LOOP_TIMEOUT tests to verify that an infinite loop is
     // aborted after a timeout.
@@ -555,7 +555,7 @@
         // Override the default loop timeout duration with a small value to
         // speed up test execution.
         constexpr int64_t kMillisecond = 1'000'000;
-        loopTimeoutDuration = 1 * kMillisecond;
+        loopTimeoutDurationNs = 1 * kMillisecond;
     }
 
     ErrorStatus executionStatus;
@@ -568,7 +568,7 @@
             ExecutionResult executionResult;
             // execute
             const auto ret = preparedModel->executeSynchronously(request, testConfig.measureTiming,
-                                                                 kNoDeadline, loopTimeoutDuration,
+                                                                 kNoDeadline, loopTimeoutDurationNs,
                                                                  &executionResult);
             ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
                     << ret.getDescription();
@@ -608,7 +608,7 @@
             ExecutionResult executionResult;
             // execute
             ret = burst->executeSynchronously(request, slots, testConfig.measureTiming, kNoDeadline,
-                                              loopTimeoutDuration, &executionResult);
+                                              loopTimeoutDurationNs, &executionResult);
             ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
                     << ret.getDescription();
             if (ret.isOk()) {
@@ -635,7 +635,7 @@
             ErrorStatus result = ErrorStatus::NONE;
             FencedExecutionResult executionResult;
             auto ret = preparedModel->executeFenced(request, {}, testConfig.measureTiming,
-                                                    kNoDeadline, loopTimeoutDuration, kNoDuration,
+                                                    kNoDeadline, loopTimeoutDurationNs, kNoDuration,
                                                     &executionResult);
             ASSERT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
                     << ret.getDescription();
@@ -649,7 +649,7 @@
                 waitFor.emplace_back(dupFd);
                 // If a sync fence is returned, try start another run waiting for the sync fence.
                 ret = preparedModel->executeFenced(request, waitFor, testConfig.measureTiming,
-                                                   kNoDeadline, loopTimeoutDuration, kNoDuration,
+                                                   kNoDeadline, loopTimeoutDurationNs, kNoDuration,
                                                    &executionResult);
                 ASSERT_TRUE(ret.isOk());
                 waitForSyncFence(executionResult.syncFence.get());
@@ -686,8 +686,8 @@
     if (!testConfig.measureTiming) {
         EXPECT_EQ(timing, kNoTiming);
     } else {
-        if (timing.timeOnDevice != -1 && timing.timeInDriver != -1) {
-            EXPECT_LE(timing.timeOnDevice, timing.timeInDriver);
+        if (timing.timeOnDeviceNs != -1 && timing.timeInDriverNs != -1) {
+            EXPECT_LE(timing.timeOnDeviceNs, timing.timeInDriverNs);
         }
     }
 
diff --git a/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp b/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp
index 627c26a..e8313f1 100644
--- a/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp
+++ b/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "neuralnetworks_aidl_hal_test"
 
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
 #include <android-base/logging.h>
 #include <android/binder_auto_utils.h>
 #include <android/binder_interface_utils.h>
@@ -337,18 +338,18 @@
                               const std::shared_ptr<IPreparedModel>& model2) {
         validateAllocate({
                 .preparedModels = {model1, model2},
-                .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
-                               {.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+                .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .probability = 1.0f},
+                               {.modelIndex = 1, .ioIndex = 0, .probability = 1.0f}},
         });
         validateAllocate({
                 .preparedModels = {model1, model2},
-                .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
-                .outputRoles = {{.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+                .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .probability = 1.0f}},
+                .outputRoles = {{.modelIndex = 1, .ioIndex = 0, .probability = 1.0f}},
         });
         validateAllocate({
                 .preparedModels = {model1, model2},
-                .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
-                                {.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+                .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .probability = 1.0f},
+                                {.modelIndex = 1, .ioIndex = 0, .probability = 1.0f}},
         });
     }
 };
@@ -370,13 +371,13 @@
     // Test with nullptr prepared model as input role.
     validateAllocate({
             .preparedModels = {nullptr},
-            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .probability = 1.0f}},
     });
 
     // Test with nullptr prepared model as output role.
     validateAllocate({
             .preparedModels = {nullptr},
-            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .probability = 1.0f}},
     });
 }
 
@@ -387,13 +388,13 @@
     // Test with invalid prepared model as input role.
     validateAllocate({
             .preparedModels = {invalidPreparedModel},
-            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .probability = 1.0f}},
     });
 
     // Test with invalid prepared model as output role.
     validateAllocate({
             .preparedModels = {invalidPreparedModel},
-            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .probability = 1.0f}},
     });
 }
 
@@ -404,13 +405,13 @@
     // This should fail, because the model index is out of bound.
     validateAllocate({
             .preparedModels = {preparedModel},
-            .inputRoles = {{.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+            .inputRoles = {{.modelIndex = 1, .ioIndex = 0, .probability = 1.0f}},
     });
 
     // This should fail, because the model index is out of bound.
     validateAllocate({
             .preparedModels = {preparedModel},
-            .outputRoles = {{.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+            .outputRoles = {{.modelIndex = 1, .ioIndex = 0, .probability = 1.0f}},
     });
 }
 
@@ -421,30 +422,30 @@
     // This should fail, because the model only has one input.
     validateAllocate({
             .preparedModels = {preparedModel},
-            .inputRoles = {{.modelIndex = 0, .ioIndex = 1, .frequency = 1.0f}},
+            .inputRoles = {{.modelIndex = 0, .ioIndex = 1, .probability = 1.0f}},
     });
 
     // This should fail, because the model only has one output.
     validateAllocate({
             .preparedModels = {preparedModel},
-            .outputRoles = {{.modelIndex = 0, .ioIndex = 1, .frequency = 1.0f}},
+            .outputRoles = {{.modelIndex = 0, .ioIndex = 1, .probability = 1.0f}},
     });
 }
 
-TEST_P(MemoryDomainAllocateTest, InvalidFrequency) {
+TEST_P(MemoryDomainAllocateTest, InvalidProbability) {
     auto preparedModel = createConvPreparedModel(kTestOperand);
     if (preparedModel == nullptr) return;
 
     for (float invalidFreq : {10.0f, 0.0f, -0.5f}) {
-        // Test with invalid frequency for input roles.
+        // Test with invalid probability for input roles.
         validateAllocate({
                 .preparedModels = {preparedModel},
-                .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = invalidFreq}},
+                .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .probability = invalidFreq}},
         });
-        // Test with invalid frequency for output roles.
+        // Test with invalid probability for output roles.
         validateAllocate({
                 .preparedModels = {preparedModel},
-                .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = invalidFreq}},
+                .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .probability = invalidFreq}},
         });
     }
 }
@@ -456,25 +457,25 @@
     // Same role with same model index.
     validateAllocate({
             .preparedModels = {preparedModel},
-            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
-                           {.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .probability = 1.0f},
+                           {.modelIndex = 0, .ioIndex = 0, .probability = 1.0f}},
     });
     validateAllocate({
             .preparedModels = {preparedModel},
-            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
-                            {.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .probability = 1.0f},
+                            {.modelIndex = 0, .ioIndex = 0, .probability = 1.0f}},
     });
 
     // Different model indexes, but logically referring to the same role.
     validateAllocate({
             .preparedModels = {preparedModel, preparedModel},
-            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
-                           {.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .probability = 1.0f},
+                           {.modelIndex = 1, .ioIndex = 0, .probability = 1.0f}},
     });
     validateAllocate({
             .preparedModels = {preparedModel, preparedModel},
-            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
-                            {.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .probability = 1.0f},
+                            {.modelIndex = 1, .ioIndex = 0, .probability = 1.0f}},
     });
 }
 
@@ -553,12 +554,12 @@
     validateAllocate({
             .dimensions = badDimensions,
             .preparedModels = {preparedModel},
-            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .probability = 1.0f}},
     });
     validateAllocate({
             .dimensions = badDimensions,
             .preparedModels = {preparedModel},
-            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .probability = 1.0f}},
     });
 }
 
@@ -572,12 +573,12 @@
     validateAllocate({
             .dimensions = badDimensions,
             .preparedModels = {preparedModel},
-            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+            .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .probability = 1.0f}},
     });
     validateAllocate({
             .dimensions = badDimensions,
             .preparedModels = {preparedModel},
-            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+            .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .probability = 1.0f}},
     });
 }
 
@@ -590,7 +591,7 @@
     validateAllocate({
             .dimensions = {1},
             .preparedModels = {preparedModel},
-            .inputRoles = {{.modelIndex = 0, .ioIndex = 2, .frequency = 1.0f}},
+            .inputRoles = {{.modelIndex = 0, .ioIndex = 2, .probability = 1.0f}},
     });
 }
 
@@ -624,7 +625,7 @@
 
         std::vector<BufferRole> inputRoles(inputIndexes.size()), outputRoles(outputIndexes.size());
         auto trans = [](int32_t ind) -> BufferRole {
-            return {.modelIndex = 0, .ioIndex = ind, .frequency = 1.0f};
+            return {.modelIndex = 0, .ioIndex = ind, .probability = 1.0f};
         };
         std::transform(inputIndexes.begin(), inputIndexes.end(), inputRoles.begin(), trans);
         std::transform(outputIndexes.begin(), outputIndexes.end(), outputRoles.begin(), trans);
@@ -659,10 +660,26 @@
         return allocateBuffer(preparedModel, inputIndexes, outputIndexes, {});
     }
 
+    size_t getSize(const Memory& memory) {
+        switch (memory.getTag()) {
+            case Memory::Tag::ashmem:
+                return memory.get<Memory::Tag::ashmem>().size;
+            case Memory::Tag::mappableFile:
+                return memory.get<Memory::Tag::mappableFile>().length;
+            case Memory::Tag::hardwareBuffer: {
+                const auto& hardwareBuffer = memory.get<Memory::Tag::hardwareBuffer>();
+                const bool isBlob =
+                        hardwareBuffer.description.format == graphics::common::PixelFormat::BLOB;
+                return isBlob ? hardwareBuffer.description.width : 0;
+            }
+        }
+        return 0;
+    }
+
     Memory allocateSharedMemory(uint32_t size) {
         const auto sharedMemory = nn::createSharedMemory(size).value();
         auto memory = utils::convert(sharedMemory).value();
-        EXPECT_EQ(memory.size, size);
+        EXPECT_EQ(getSize(memory), size);
         return memory;
     }
 
@@ -690,7 +707,7 @@
 
     void initializeDeviceMemory(const std::shared_ptr<IBuffer>& buffer) {
         Memory memory = allocateSharedMemory(kTestOperandDataSize);
-        ASSERT_EQ(memory.size, kTestOperandDataSize);
+        ASSERT_EQ(getSize(memory), kTestOperandDataSize);
         testCopyFrom(buffer, memory, utils::toSigned(kTestOperand.dimensions).value(),
                      ErrorStatus::NONE);
     }
diff --git a/neuralnetworks/aidl/vts/functional/QualityOfServiceTests.cpp b/neuralnetworks/aidl/vts/functional/QualityOfServiceTests.cpp
index 9ace1a9..bbba887 100644
--- a/neuralnetworks/aidl/vts/functional/QualityOfServiceTests.cpp
+++ b/neuralnetworks/aidl/vts/functional/QualityOfServiceTests.cpp
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
+#include <android-base/chrono_utils.h>
 #include <android/binder_enums.h>
 #include <android/binder_interface_utils.h>
 #include <android/binder_status.h>
-
 #include <nnapi/hal/aidl/Conversions.h>
 
 #include "Callbacks.h"
@@ -53,7 +53,7 @@
 
 using ExecutionFunction =
         std::function<MaybeResults(const std::shared_ptr<IPreparedModel>& preparedModel,
-                                   const Request& request, int64_t deadline)>;
+                                   const Request& request, int64_t deadlineNs)>;
 
 static int64_t makeDeadline(DeadlineBoundType deadlineBoundType) {
     const auto getNanosecondsSinceEpoch = [](const auto& time) -> int64_t {
@@ -61,16 +61,16 @@
         return std::chrono::duration_cast<std::chrono::nanoseconds>(timeSinceEpoch).count();
     };
 
-    std::chrono::steady_clock::time_point timePoint;
+    ::android::base::boot_clock::time_point timePoint;
     switch (deadlineBoundType) {
         case DeadlineBoundType::NOW:
-            timePoint = std::chrono::steady_clock::now();
+            timePoint = ::android::base::boot_clock::now();
             break;
         case DeadlineBoundType::UNLIMITED:
-            timePoint = std::chrono::steady_clock::time_point::max();
+            timePoint = ::android::base::boot_clock::time_point::max();
             break;
         case DeadlineBoundType::SHORT:
-            timePoint = std::chrono::steady_clock::now() + kShortDuration;
+            timePoint = ::android::base::boot_clock::now() + kShortDuration;
             break;
     }
 
@@ -79,9 +79,9 @@
 
 void runPrepareModelTest(const std::shared_ptr<IDevice>& device, const Model& model,
                          Priority priority, std::optional<DeadlineBoundType> deadlineBound) {
-    int64_t deadline = kNoDeadline;
+    int64_t deadlineNs = kNoDeadline;
     if (deadlineBound.has_value()) {
-        deadline = makeDeadline(deadlineBound.value());
+        deadlineNs = makeDeadline(deadlineBound.value());
     }
 
     // see if service can handle model
@@ -96,8 +96,8 @@
     const std::shared_ptr<PreparedModelCallback> preparedModelCallback =
             ndk::SharedRefBase::make<PreparedModelCallback>();
     const auto prepareLaunchStatus =
-            device->prepareModel(model, ExecutionPreference::FAST_SINGLE_ANSWER, priority, deadline,
-                                 {}, {}, kEmptyCacheToken, preparedModelCallback);
+            device->prepareModel(model, ExecutionPreference::FAST_SINGLE_ANSWER, priority,
+                                 deadlineNs, {}, {}, kEmptyCacheToken, preparedModelCallback);
     ASSERT_TRUE(prepareLaunchStatus.isOk())
             << "prepareLaunchStatus: " << prepareLaunchStatus.getDescription();
 
@@ -156,13 +156,13 @@
 }
 
 static MaybeResults executeSynchronously(const std::shared_ptr<IPreparedModel>& preparedModel,
-                                         const Request& request, int64_t deadline) {
+                                         const Request& request, int64_t deadlineNs) {
     SCOPED_TRACE("synchronous");
     const bool measure = false;
 
     // run execution
     ExecutionResult executionResult;
-    const auto ret = preparedModel->executeSynchronously(request, measure, deadline,
+    const auto ret = preparedModel->executeSynchronously(request, measure, deadlineNs,
                                                          kOmittedTimeoutDuration, &executionResult);
     EXPECT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
             << ret.getDescription();
@@ -182,7 +182,7 @@
 }
 
 static MaybeResults executeBurst(const std::shared_ptr<IPreparedModel>& preparedModel,
-                                 const Request& request, int64_t deadline) {
+                                 const Request& request, int64_t deadlineNs) {
     SCOPED_TRACE("burst");
     const bool measure = false;
 
@@ -200,7 +200,7 @@
 
     // run execution
     ExecutionResult executionResult;
-    ret = burst->executeSynchronously(request, slots, measure, deadline, kOmittedTimeoutDuration,
+    ret = burst->executeSynchronously(request, slots, measure, deadlineNs, kOmittedTimeoutDuration,
                                       &executionResult);
     EXPECT_TRUE(ret.isOk() || ret.getExceptionCode() == EX_SERVICE_SPECIFIC)
             << ret.getDescription();
@@ -224,10 +224,10 @@
                       const ExecutionContext& context, bool synchronous,
                       DeadlineBoundType deadlineBound) {
     const ExecutionFunction execute = synchronous ? executeSynchronously : executeBurst;
-    const auto deadline = makeDeadline(deadlineBound);
+    const auto deadlineNs = makeDeadline(deadlineBound);
 
     // Perform execution and unpack results.
-    const auto results = execute(preparedModel, request, deadline);
+    const auto results = execute(preparedModel, request, deadlineNs);
     if (!results.has_value()) return;
     const auto& [status, outputShapes, timing] = results.value();
 
diff --git a/neuralnetworks/aidl/vts/functional/Utils.h b/neuralnetworks/aidl/vts/functional/Utils.h
index 266301c..77085a7 100644
--- a/neuralnetworks/aidl/vts/functional/Utils.h
+++ b/neuralnetworks/aidl/vts/functional/Utils.h
@@ -43,7 +43,7 @@
 
 inline constexpr Priority kDefaultPriority = Priority::MEDIUM;
 
-inline constexpr Timing kNoTiming = {.timeOnDevice = -1, .timeInDriver = -1};
+inline constexpr Timing kNoTiming = {.timeOnDeviceNs = -1, .timeInDriverNs = -1};
 inline constexpr int64_t kNoDeadline = -1;
 inline constexpr int64_t kOmittedTimeoutDuration = -1;
 inline constexpr int64_t kNoDuration = -1;
diff --git a/neuralnetworks/aidl/vts/functional/ValidateModel.cpp b/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
index 6d84e1e..698c054 100644
--- a/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
@@ -259,12 +259,16 @@
 size_t sizeForBinder(const Memory& memory) {
     // This is just a guess.
 
-    size_t size = 0;
-    const NativeHandle& handle = memory.handle;
-    size += sizeof(decltype(handle.fds)::value_type) * handle.fds.size();
-    size += sizeof(decltype(handle.ints)::value_type) * handle.ints.size();
-    size += sizeForBinder(memory.name);
-    size += sizeof(memory);
+    size_t size = sizeof(Memory);
+
+    // Only hardwareBuffer type memory has dynamic memory that needs to be accounted for (in the
+    // form of a NativeHandle type). The other other types of memory (MappableFile, Ashmem) use a
+    // single file descriptor (with metadata) instead.
+    if (memory.getTag() == Memory::Tag::hardwareBuffer) {
+        const NativeHandle& handle = memory.get<Memory::Tag::hardwareBuffer>().handle;
+        size += sizeof(decltype(handle.fds)::value_type) * handle.fds.size();
+        size += sizeof(decltype(handle.ints)::value_type) * handle.ints.size();
+    }
 
     return size;
 }
@@ -1312,7 +1316,7 @@
 void validateModel(const std::shared_ptr<IDevice>& device, const Model& model) {
     const auto numberOfConsumers =
             nn::countNumberOfConsumers(model.main.operands.size(),
-                                       nn::convert(model.main.operations).value())
+                                       nn::unvalidatedConvert(model.main.operations).value())
                     .value();
     mutateExecutionOrderTest(device, model, numberOfConsumers);
     mutateOperandTypeTest(device, model);
diff --git a/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp
index 0c3a196..ee7cf89 100644
--- a/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp
@@ -94,7 +94,7 @@
 }
 
 static NamedDevice makeNamedDevice(const std::string& name) {
-    ndk::SpAIBinder binder(AServiceManager_getService(name.c_str()));
+    ndk::SpAIBinder binder(AServiceManager_waitForService(name.c_str()));
     return {name, IDevice::fromBinder(binder)};
 }
 
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h
index 996858c..17b3fd9 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h
@@ -32,7 +32,9 @@
     OptionalCacheHold cacheMemory(const nn::SharedMemory& memory) const override;
 
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
-            const nn::Request& request, nn::MeasureTiming measure) const override;
+            const nn::Request& request, nn::MeasureTiming measure,
+            const nn::OptionalTimePoint& deadline,
+            const nn::OptionalDuration& loopTimeoutDuration) const override;
 };
 
 }  // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h
index 3b87330..c92cc41 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h
@@ -47,7 +47,9 @@
     OptionalCacheHold cacheMemory(const nn::SharedMemory& memory) const override;
 
     nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
-            const nn::Request& request, nn::MeasureTiming measure) const override;
+            const nn::Request& request, nn::MeasureTiming measure,
+            const nn::OptionalTimePoint& deadline,
+            const nn::OptionalDuration& loopTimeoutDuration) const override;
 
   private:
     const Factory kMakeBurst;
diff --git a/neuralnetworks/utils/common/src/CommonUtils.cpp b/neuralnetworks/utils/common/src/CommonUtils.cpp
index 924ecb2..4d26795 100644
--- a/neuralnetworks/utils/common/src/CommonUtils.cpp
+++ b/neuralnetworks/utils/common/src/CommonUtils.cpp
@@ -89,6 +89,59 @@
                   });
 }
 
+nn::GeneralResult<hidl_handle> createNativeHandleFrom(base::unique_fd fd,
+                                                      const std::vector<int32_t>& ints) {
+    constexpr size_t kIntMax = std::numeric_limits<int>::max();
+    CHECK_LE(ints.size(), kIntMax);
+    native_handle_t* nativeHandle = native_handle_create(1, static_cast<int>(ints.size()));
+    if (nativeHandle == nullptr) {
+        return NN_ERROR() << "Failed to create native_handle";
+    }
+
+    nativeHandle->data[0] = fd.release();
+    std::copy(ints.begin(), ints.end(), nativeHandle->data + 1);
+
+    hidl_handle handle;
+    handle.setTo(nativeHandle, /*shouldOwn=*/true);
+    return handle;
+}
+
+nn::GeneralResult<hidl_memory> createHidlMemoryFrom(const nn::Memory::Ashmem& memory) {
+    auto fd = NN_TRY(nn::dupFd(memory.fd));
+    auto handle = NN_TRY(createNativeHandleFrom(std::move(fd), {}));
+    return hidl_memory("ashmem", std::move(handle), memory.size);
+}
+
+nn::GeneralResult<hidl_memory> createHidlMemoryFrom(const nn::Memory::Fd& memory) {
+    auto fd = NN_TRY(nn::dupFd(memory.fd));
+
+    const auto [lowOffsetBits, highOffsetBits] = nn::getIntsFromOffset(memory.offset);
+    const std::vector<int> ints = {memory.prot, lowOffsetBits, highOffsetBits};
+
+    auto handle = NN_TRY(createNativeHandleFrom(std::move(fd), ints));
+    return hidl_memory("mmap_fd", std::move(handle), memory.size);
+}
+
+nn::GeneralResult<hidl_memory> createHidlMemoryFrom(const nn::Memory::HardwareBuffer& memory) {
+    const auto* ahwb = memory.handle.get();
+    AHardwareBuffer_Desc bufferDesc;
+    AHardwareBuffer_describe(ahwb, &bufferDesc);
+
+    const bool isBlob = bufferDesc.format == AHARDWAREBUFFER_FORMAT_BLOB;
+    const size_t size = isBlob ? bufferDesc.width : 0;
+    const char* const name = isBlob ? "hardware_buffer_blob" : "hardware_buffer";
+
+    const native_handle_t* nativeHandle = AHardwareBuffer_getNativeHandle(ahwb);
+    const hidl_handle hidlHandle(nativeHandle);
+    hidl_handle copiedHandle(hidlHandle);
+
+    return hidl_memory(name, std::move(copiedHandle), size);
+}
+
+nn::GeneralResult<hidl_memory> createHidlMemoryFrom(const nn::Memory::Unknown& memory) {
+    return hidl_memory(memory.name, NN_TRY(hidlHandleFromSharedHandle(memory.handle)), memory.size);
+}
+
 }  // anonymous namespace
 
 nn::Capabilities::OperandPerformanceTable makeQuantized8PerformanceConsistentWithP(
@@ -255,27 +308,7 @@
     if (memory == nullptr) {
         return NN_ERROR() << "Memory must be non-empty";
     }
-    if (const auto* handle = std::get_if<nn::Handle>(&memory->handle)) {
-        return hidl_memory(memory->name, NN_TRY(hidlHandleFromSharedHandle(*handle)), memory->size);
-    }
-
-    const auto* ahwb = std::get<nn::HardwareBufferHandle>(memory->handle).get();
-    AHardwareBuffer_Desc bufferDesc;
-    AHardwareBuffer_describe(ahwb, &bufferDesc);
-
-    if (bufferDesc.format == AHARDWAREBUFFER_FORMAT_BLOB) {
-        CHECK_EQ(memory->size, bufferDesc.width);
-        CHECK_EQ(memory->name, "hardware_buffer_blob");
-    } else {
-        CHECK_EQ(memory->size, 0u);
-        CHECK_EQ(memory->name, "hardware_buffer");
-    }
-
-    const native_handle_t* nativeHandle = AHardwareBuffer_getNativeHandle(ahwb);
-    const hidl_handle hidlHandle(nativeHandle);
-    hidl_handle handle(hidlHandle);
-
-    return hidl_memory(memory->name, std::move(handle), memory->size);
+    return std::visit([](const auto& x) { return createHidlMemoryFrom(x); }, memory->handle);
 }
 
 static uint32_t roundUpToMultiple(uint32_t value, uint32_t multiple) {
@@ -283,14 +316,53 @@
 }
 
 nn::GeneralResult<nn::SharedMemory> createSharedMemoryFromHidlMemory(const hidl_memory& memory) {
-    CHECK_LE(memory.size(), std::numeric_limits<uint32_t>::max());
+    CHECK_LE(memory.size(), std::numeric_limits<size_t>::max());
+    if (!memory.valid()) {
+        return NN_ERROR() << "Unable to convert invalid hidl_memory";
+    }
+
+    if (memory.name() == "ashmem") {
+        if (memory.handle()->numFds != 1) {
+            return NN_ERROR() << "Unable to convert invalid ashmem memory object with "
+                              << memory.handle()->numFds << " numFds, but expected 1";
+        }
+        if (memory.handle()->numInts != 0) {
+            return NN_ERROR() << "Unable to convert invalid ashmem memory object with "
+                              << memory.handle()->numInts << " numInts, but expected 0";
+        }
+        auto handle = nn::Memory::Ashmem{
+                .fd = NN_TRY(nn::dupFd(memory.handle()->data[0])),
+                .size = static_cast<size_t>(memory.size()),
+        };
+        return std::make_shared<const nn::Memory>(nn::Memory{.handle = std::move(handle)});
+    }
+
+    if (memory.name() == "mmap_fd") {
+        if (memory.handle()->numFds != 1) {
+            return NN_ERROR() << "Unable to convert invalid mmap_fd memory object with "
+                              << memory.handle()->numFds << " numFds, but expected 1";
+        }
+        if (memory.handle()->numInts != 3) {
+            return NN_ERROR() << "Unable to convert invalid mmap_fd memory object with "
+                              << memory.handle()->numInts << " numInts, but expected 3";
+        }
+
+        const int fd = memory.handle()->data[0];
+        const int prot = memory.handle()->data[1];
+        const int lower = memory.handle()->data[2];
+        const int higher = memory.handle()->data[3];
+        const size_t offset = nn::getOffsetFromInts(lower, higher);
+
+        return nn::createSharedMemoryFromFd(static_cast<size_t>(memory.size()), prot, fd, offset);
+    }
 
     if (memory.name() != "hardware_buffer_blob") {
-        return std::make_shared<const nn::Memory>(nn::Memory{
+        auto handle = nn::Memory::Unknown{
                 .handle = NN_TRY(sharedHandleFromNativeHandle(memory.handle())),
-                .size = static_cast<uint32_t>(memory.size()),
+                .size = static_cast<size_t>(memory.size()),
                 .name = memory.name(),
-        });
+        };
+        return std::make_shared<const nn::Memory>(nn::Memory{.handle = std::move(handle)});
     }
 
     const auto size = memory.size();
@@ -328,11 +400,7 @@
                << "Can't create AHardwareBuffer from handle. Error: " << status;
     }
 
-    return std::make_shared<const nn::Memory>(nn::Memory{
-            .handle = nn::HardwareBufferHandle(hardwareBuffer, /*takeOwnership=*/true),
-            .size = static_cast<uint32_t>(memory.size()),
-            .name = memory.name(),
-    });
+    return nn::createSharedMemoryFromAHWB(hardwareBuffer, /*takeOwnership=*/true);
 }
 
 nn::GeneralResult<hidl_handle> hidlHandleFromSharedHandle(const nn::Handle& handle) {
diff --git a/neuralnetworks/utils/common/src/InvalidBurst.cpp b/neuralnetworks/utils/common/src/InvalidBurst.cpp
index 81ca18d..0c34f05 100644
--- a/neuralnetworks/utils/common/src/InvalidBurst.cpp
+++ b/neuralnetworks/utils/common/src/InvalidBurst.cpp
@@ -32,7 +32,9 @@
 }
 
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> InvalidBurst::execute(
-        const nn::Request& /*request*/, nn::MeasureTiming /*measure*/) const {
+        const nn::Request& /*request*/, nn::MeasureTiming /*measure*/,
+        const nn::OptionalTimePoint& /*deadline*/,
+        const nn::OptionalDuration& /*loopTimeoutDuration*/) const {
     return NN_ERROR() << "InvalidBurst";
 }
 
diff --git a/neuralnetworks/utils/common/src/ResilientBurst.cpp b/neuralnetworks/utils/common/src/ResilientBurst.cpp
index 5ca868b..38ccc62 100644
--- a/neuralnetworks/utils/common/src/ResilientBurst.cpp
+++ b/neuralnetworks/utils/common/src/ResilientBurst.cpp
@@ -100,9 +100,11 @@
 }
 
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> ResilientBurst::execute(
-        const nn::Request& request, nn::MeasureTiming measure) const {
-    const auto fn = [&request, measure](const nn::IBurst& burst) {
-        return burst.execute(request, measure);
+        const nn::Request& request, nn::MeasureTiming measure,
+        const nn::OptionalTimePoint& deadline,
+        const nn::OptionalDuration& loopTimeoutDuration) const {
+    const auto fn = [&request, measure, deadline, loopTimeoutDuration](const nn::IBurst& burst) {
+        return burst.execute(request, measure, deadline, loopTimeoutDuration);
     };
     return protect(*this, fn);
 }
diff --git a/neuralnetworks/utils/common/test/MockBuffer.h b/neuralnetworks/utils/common/test/MockBuffer.h
index 59d5700..3599d0c 100644
--- a/neuralnetworks/utils/common/test/MockBuffer.h
+++ b/neuralnetworks/utils/common/test/MockBuffer.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_BUFFER
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_BUFFER
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_BUFFER_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_BUFFER_H
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -34,4 +34,4 @@
 
 }  // namespace android::nn
 
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_BUFFER
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_BUFFER_H
diff --git a/neuralnetworks/utils/common/test/MockDevice.h b/neuralnetworks/utils/common/test/MockDevice.h
index 5566968..b274716 100644
--- a/neuralnetworks/utils/common/test/MockDevice.h
+++ b/neuralnetworks/utils/common/test/MockDevice.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_DEVICE
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_DEVICE
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_DEVICE_H
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -55,4 +55,4 @@
 
 }  // namespace android::nn
 
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_DEVICE
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_DEVICE_H
diff --git a/neuralnetworks/utils/common/test/MockPreparedModel.h b/neuralnetworks/utils/common/test/MockPreparedModel.h
index 418af61..c004861 100644
--- a/neuralnetworks/utils/common/test/MockPreparedModel.h
+++ b/neuralnetworks/utils/common/test/MockPreparedModel.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_PREPARED_MODEL
-#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_PREPARED_MODEL
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_PREPARED_MODEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_PREPARED_MODEL_H
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -41,4 +41,4 @@
 
 }  // namespace android::nn
 
-#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_PREPARED_MODEL
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_TEST_MOCK_PREPARED_MODEL_H
diff --git a/neuralnetworks/utils/service/src/Service.cpp b/neuralnetworks/utils/service/src/Service.cpp
index c83bcc9..75ab1f9 100644
--- a/neuralnetworks/utils/service/src/Service.cpp
+++ b/neuralnetworks/utils/service/src/Service.cpp
@@ -16,6 +16,7 @@
 
 #include "Service.h"
 
+#include <AndroidVersionUtil.h>
 #include <aidl/android/hardware/neuralnetworks/IDevice.h>
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
@@ -82,7 +83,7 @@
 
     // Devices with SDK level lower than 31 (Android S) don't have any AIDL drivers available, so
     // there is no need for a workaround supported on lower levels.
-    if (__builtin_available(android __ANDROID_API_S__, *)) {
+    if (__builtin_available(android __NNAPI_AIDL_MIN_ANDROID_API__, *)) {
         AServiceManager_forEachDeclaredInstance(aidl_hal::IDevice::descriptor,
                                                 static_cast<void*>(&names), callback);
     }
diff --git a/power/aidl/Android.bp b/power/aidl/Android.bp
index 054fea5..dbd18fd 100644
--- a/power/aidl/Android.bp
+++ b/power/aidl/Android.bp
@@ -29,6 +29,9 @@
     ],
     stability: "vintf",
     backend: {
+        cpp: {
+            enabled: true,
+        },
         java: {
             platform_apis: true,
         },
@@ -38,5 +41,7 @@
             },
         },
     },
-    versions: ["1"],
+    versions: [
+        "1",
+    ],
 }
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Boost.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Boost.aidl
index aced215..c792d4e 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Boost.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Boost.aidl
@@ -1,14 +1,30 @@
+/*
+ * 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.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// 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 changes to the AIDL files built
+// 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
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl
index 8a06623..ae03313 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPower.aidl
@@ -1,14 +1,30 @@
+/*
+ * 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.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// 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 changes to the AIDL files built
+// 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
@@ -22,4 +38,6 @@
   boolean isModeSupported(in android.hardware.power.Mode type);
   oneway void setBoost(in android.hardware.power.Boost type, in int durationMs);
   boolean isBoostSupported(in android.hardware.power.Boost type);
+  android.hardware.power.IPowerHintSession createHintSession(in int tgid, in int uid, in int[] threadIds, in long durationNanos);
+  long getHintSessionPreferredRate();
 }
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
similarity index 78%
copy from biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
copy to power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
index 4db47c9..1d3ecb7 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
@@ -31,21 +31,12 @@
 // 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.biometrics.face;
-@Backing(type="byte") @VintfStability
-enum SessionState {
-  IDLING = 0,
-  CLOSED = 1,
-  GENERATING_CHALLENGE = 2,
-  REVOKING_CHALLENGE = 3,
-  ENROLLING = 4,
-  AUTHENTICATING = 5,
-  DETECTING_INTERACTION = 6,
-  ENUMERATING_ENROLLMENTS = 7,
-  REMOVING_ENROLLMENTS = 8,
-  GETTING_FEATURES = 9,
-  SETTING_FEATURE = 10,
-  GETTING_AUTHENTICATOR_ID = 11,
-  INVALIDATING_AUTHENTICATOR_ID = 12,
-  RESETTING_LOCKOUT = 13,
+package android.hardware.power;
+@VintfStability
+interface IPowerHintSession {
+  oneway void updateTargetWorkDuration(long targetDurationNanos);
+  oneway void reportActualWorkDuration(in android.hardware.power.WorkDuration[] durations);
+  oneway void pause();
+  oneway void resume();
+  oneway void close();
 }
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl
index f7c2552..8920c01 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/Mode.aidl
@@ -1,14 +1,30 @@
+/*
+ * 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.
+ */
 ///////////////////////////////////////////////////////////////////////////////
 // THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
-// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// 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 changes to the AIDL files built
+// 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
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/WorkDuration.aidl
similarity index 78%
copy from biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
copy to power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/WorkDuration.aidl
index 4db47c9..e86cd40 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/WorkDuration.aidl
@@ -31,21 +31,9 @@
 // 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.biometrics.face;
-@Backing(type="byte") @VintfStability
-enum SessionState {
-  IDLING = 0,
-  CLOSED = 1,
-  GENERATING_CHALLENGE = 2,
-  REVOKING_CHALLENGE = 3,
-  ENROLLING = 4,
-  AUTHENTICATING = 5,
-  DETECTING_INTERACTION = 6,
-  ENUMERATING_ENROLLMENTS = 7,
-  REMOVING_ENROLLMENTS = 8,
-  GETTING_FEATURES = 9,
-  SETTING_FEATURE = 10,
-  GETTING_AUTHENTICATOR_ID = 11,
-  INVALIDATING_AUTHENTICATOR_ID = 12,
-  RESETTING_LOCKOUT = 13,
+package android.hardware.power;
+@VintfStability
+parcelable WorkDuration {
+  long timeStampNanos;
+  long durationNanos;
 }
diff --git a/power/aidl/android/hardware/power/IPower.aidl b/power/aidl/android/hardware/power/IPower.aidl
index 2c4bd86..ee8e5a3 100644
--- a/power/aidl/android/hardware/power/IPower.aidl
+++ b/power/aidl/android/hardware/power/IPower.aidl
@@ -17,6 +17,7 @@
 package android.hardware.power;
 
 import android.hardware.power.Boost;
+import android.hardware.power.IPowerHintSession;
 import android.hardware.power.Mode;
 
 @VintfStability
@@ -69,4 +70,37 @@
      * @param type Boost to be queried
      */
     boolean isBoostSupported(in Boost type);
+
+    /**
+     * A Session represents a group of threads with an inter-related workload such that hints for
+     * their performance should be considered as a unit. The threads in a given session should be
+     * long-life and not created or destroyed dynamically.
+     *
+     * Each session is expected to have a periodic workload with a target duration for each
+     * cycle. The cycle duration is likely greater than the target work duration to allow other
+     * parts of the pipeline to run within the available budget. For example, a renderer thread may
+     * work at 60hz in order to produce frames at the display's frame but have a target work
+     * duration of only 6ms.
+     *
+     * Creates a session for the given set of threads and sets their initial target work
+     * duration.
+     *
+     * @return  the new session if it is supported on this device, otherwise return with
+     *          EX_UNSUPPORTED_OPERATION error if hint session is not supported on this device.
+     * @param   tgid The TGID to be associated with this session.
+     * @param   uid The UID to be associated with this session.
+     * @param   threadIds The list of threads to be associated with this session.
+     * @param   durationNanos The desired duration in nanoseconds for this session.
+     */
+    IPowerHintSession createHintSession(
+            in int tgid, in int uid, in int[] threadIds, in long durationNanos);
+
+    /**
+     * Get preferred update rate (interval) information for this device. Framework must communicate
+     * this rate to Apps, and also ensure the session hint sent no faster than the update rate.
+     *
+     * @return the preferred update rate in nanoseconds supported by device software. Return with
+     *         EX_UNSUPPORTED_OPERATION if hint session is not supported.
+     */
+    long getHintSessionPreferredRate();
 }
diff --git a/power/aidl/android/hardware/power/IPowerHintSession.aidl b/power/aidl/android/hardware/power/IPowerHintSession.aidl
new file mode 100644
index 0000000..c289448
--- /dev/null
+++ b/power/aidl/android/hardware/power/IPowerHintSession.aidl
@@ -0,0 +1,59 @@
+/*
+ * 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.power;
+
+import android.hardware.power.WorkDuration;
+
+@VintfStability
+oneway interface IPowerHintSession {
+    /**
+     * Updates the desired duration of a previously-created thread group.
+     *
+     * See {@link IPowerHintSession#createHintSession} for more information on how
+     * the desired duration will be used.
+     *
+     * @param targetDurationNanos the new desired duration in nanoseconds
+     */
+    void updateTargetWorkDuration(long targetDurationNanos);
+
+    /**
+     * Reports the actual duration of a thread group.
+     *
+     * The system will attempt to adjust the core placement of the threads within
+     * the thread group and/or the frequency of the core on which they are run to bring
+     * the actual duration close to the target duration.
+     *
+     * @param actualDurationMicros how long the thread group took to complete its
+     *        last task in nanoseconds
+     */
+    void reportActualWorkDuration(in WorkDuration[] durations);
+
+    /**
+     * Pause the session when the application is not allowed to send hint in framework.
+     */
+    void pause();
+
+    /**
+     * Resume the session when the application is allowed to send hint in framework.
+     */
+    void resume();
+
+    /**
+     * Close the session to release resources.
+     */
+    void close();
+}
diff --git a/power/aidl/android/hardware/power/WorkDuration.aidl b/power/aidl/android/hardware/power/WorkDuration.aidl
new file mode 100644
index 0000000..a06a058
--- /dev/null
+++ b/power/aidl/android/hardware/power/WorkDuration.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.power;
+
+@VintfStability
+parcelable WorkDuration {
+    /**
+     * Time stamp in nanoseconds based on CLOCK_MONOTONIC when the duration
+     * sample was measured.
+     */
+    long timeStampNanos;
+    /**
+     * Work duration in nanoseconds.
+     */
+    long durationNanos;
+}
diff --git a/power/aidl/default/Android.bp b/power/aidl/default/Android.bp
index 5aa6893..c0ba9a0 100644
--- a/power/aidl/default/Android.bp
+++ b/power/aidl/default/Android.bp
@@ -30,7 +30,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.power-V1-ndk_platform",
+        "android.hardware.power-V2-ndk_platform",
     ],
     srcs: [
         "main.cpp",
diff --git a/power/aidl/default/Power.cpp b/power/aidl/default/Power.cpp
index 8610de3..7f08f44 100644
--- a/power/aidl/default/Power.cpp
+++ b/power/aidl/default/Power.cpp
@@ -25,6 +25,10 @@
 namespace impl {
 namespace example {
 
+const std::vector<Boost> BOOST_RANGE{ndk::enum_range<Boost>().begin(),
+                                     ndk::enum_range<Boost>().end()};
+const std::vector<Mode> MODE_RANGE{ndk::enum_range<Mode>().begin(), ndk::enum_range<Mode>().end()};
+
 ndk::ScopedAStatus Power::setMode(Mode type, bool enabled) {
     LOG(VERBOSE) << "Power setMode: " << static_cast<int32_t>(type) << " to: " << enabled;
     return ndk::ScopedAStatus::ok();
@@ -32,7 +36,7 @@
 
 ndk::ScopedAStatus Power::isModeSupported(Mode type, bool* _aidl_return) {
     LOG(INFO) << "Power isModeSupported: " << static_cast<int32_t>(type);
-    *_aidl_return = false;
+    *_aidl_return = type >= MODE_RANGE.front() && type <= MODE_RANGE.back();
     return ndk::ScopedAStatus::ok();
 }
 
@@ -44,10 +48,21 @@
 
 ndk::ScopedAStatus Power::isBoostSupported(Boost type, bool* _aidl_return) {
     LOG(INFO) << "Power isBoostSupported: " << static_cast<int32_t>(type);
-    *_aidl_return = false;
+    *_aidl_return = type >= BOOST_RANGE.front() && type <= BOOST_RANGE.back();
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Power::createHintSession(int32_t, int32_t, const std::vector<int32_t>&, int64_t,
+                                            std::shared_ptr<IPowerHintSession>* _aidl_return) {
+    *_aidl_return = nullptr;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Power::getHintSessionPreferredRate(int64_t* outNanoseconds) {
+    *outNanoseconds = -1;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
 }  // namespace example
 }  // namespace impl
 }  // namespace power
diff --git a/power/aidl/default/Power.h b/power/aidl/default/Power.h
index f7645aa..ef6439d 100644
--- a/power/aidl/default/Power.h
+++ b/power/aidl/default/Power.h
@@ -30,6 +30,11 @@
     ndk::ScopedAStatus isModeSupported(Mode type, bool* _aidl_return) override;
     ndk::ScopedAStatus setBoost(Boost type, int32_t durationMs) override;
     ndk::ScopedAStatus isBoostSupported(Boost type, bool* _aidl_return) override;
+    ndk::ScopedAStatus createHintSession(int32_t tgid, int32_t uid,
+                                         const std::vector<int32_t>& threadIds,
+                                         int64_t durationNanos,
+                                         std::shared_ptr<IPowerHintSession>* _aidl_return) override;
+    ndk::ScopedAStatus getHintSessionPreferredRate(int64_t* outNanoseconds) override;
 };
 
 }  // namespace example
diff --git a/power/aidl/default/power-default.xml b/power/aidl/default/power-default.xml
index caf6ea2..9f56deb 100644
--- a/power/aidl/default/power-default.xml
+++ b/power/aidl/default/power-default.xml
@@ -1,6 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.power</name>
+        <version>2</version>
         <fqname>IPower/default</fqname>
     </hal>
 </manifest>
diff --git a/power/aidl/vts/Android.bp b/power/aidl/vts/Android.bp
index 1051b03..3036b82 100644
--- a/power/aidl/vts/Android.bp
+++ b/power/aidl/vts/Android.bp
@@ -29,10 +29,10 @@
     ],
     srcs: ["VtsHalPowerTargetTest.cpp"],
     shared_libs: [
-        "libbinder",
+        "libbinder_ndk",
     ],
     static_libs: [
-        "android.hardware.power-V1-cpp",
+        "android.hardware.power-V2-ndk_platform",
     ],
     test_suites: [
         "vts",
diff --git a/power/aidl/vts/VtsHalPowerTargetTest.cpp b/power/aidl/vts/VtsHalPowerTargetTest.cpp
index d036c90..5bb088a 100644
--- a/power/aidl/vts/VtsHalPowerTargetTest.cpp
+++ b/power/aidl/vts/VtsHalPowerTargetTest.cpp
@@ -16,29 +16,28 @@
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
 
+#include <aidl/android/hardware/power/BnPower.h>
+#include <aidl/android/hardware/power/BnPowerHintSession.h>
 #include <android-base/properties.h>
-#include <android/hardware/power/Boost.h>
-#include <android/hardware/power/IPower.h>
-#include <android/hardware/power/Mode.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
 
-#include <future>
+#include <unistd.h>
 
-using android::ProcessState;
-using android::sp;
-using android::String16;
-using android::base::GetUintProperty;
-using android::binder::Status;
+namespace aidl::android::hardware::power {
+namespace {
+
+using ::android::base::GetUintProperty;
 using android::hardware::power::Boost;
 using android::hardware::power::IPower;
+using android::hardware::power::IPowerHintSession;
 using android::hardware::power::Mode;
+using android::hardware::power::WorkDuration;
 
-const std::vector<Boost> kBoosts{android::enum_range<Boost>().begin(),
-                                 android::enum_range<Boost>().end()};
+const std::vector<Boost> kBoosts{ndk::enum_range<Boost>().begin(), ndk::enum_range<Boost>().end()};
 
-const std::vector<Mode> kModes{android::enum_range<Mode>().begin(),
-                               android::enum_range<Mode>().end()};
+const std::vector<Mode> kModes{ndk::enum_range<Mode>().begin(), ndk::enum_range<Mode>().end()};
 
 const std::vector<Boost> kInvalidBoosts = {
         static_cast<Boost>(static_cast<int32_t>(kBoosts.front()) - 1),
@@ -50,14 +49,48 @@
         static_cast<Mode>(static_cast<int32_t>(kModes.back()) + 1),
 };
 
+class DurationWrapper : public WorkDuration {
+  public:
+    DurationWrapper(int64_t dur, int64_t time) {
+        durationNanos = dur;
+        timeStampNanos = time;
+    }
+};
+
+const std::vector<int32_t> kSelfTids = {
+        gettid(),
+};
+
+const std::vector<int32_t> kEmptyTids = {};
+
+const std::vector<WorkDuration> kNoDurations = {};
+
+const std::vector<WorkDuration> kDurationsWithZero = {
+        DurationWrapper(1000L, 1L),
+        DurationWrapper(0L, 2L),
+};
+
+const std::vector<WorkDuration> kDurationsWithNegative = {
+        DurationWrapper(1000L, 1L),
+        DurationWrapper(-1000L, 2L),
+};
+
+const std::vector<WorkDuration> kDurations = {
+        DurationWrapper(1L, 1L),
+        DurationWrapper(1000L, 2L),
+        DurationWrapper(1000000L, 3L),
+        DurationWrapper(1000000000L, 4L),
+};
+
 class PowerAidl : public testing::TestWithParam<std::string> {
   public:
     virtual void SetUp() override {
-        power = android::waitForDeclaredService<IPower>(String16(GetParam().c_str()));
-        ASSERT_NE(power, nullptr);
+        AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
+        ASSERT_NE(binder, nullptr);
+        power = IPower::fromBinder(ndk::SpAIBinder(binder));
     }
 
-    sp<IPower> power;
+    std::shared_ptr<IPower> power;
 };
 
 TEST_P(PowerAidl, setMode) {
@@ -110,6 +143,56 @@
     }
 }
 
+TEST_P(PowerAidl, getHintSessionPreferredRate) {
+    int64_t rate = -1;
+    auto status = power->getHintSessionPreferredRate(&rate);
+    if (!status.isOk()) {
+        ASSERT_EQ(EX_UNSUPPORTED_OPERATION, status.getExceptionCode());
+        return;
+    }
+
+    // At least 1ms rate limit from HAL
+    ASSERT_GE(rate, 1000000);
+}
+
+TEST_P(PowerAidl, createAndCloseHintSession) {
+    std::shared_ptr<IPowerHintSession> session;
+    auto status = power->createHintSession(getpid(), getuid(), kSelfTids, 16666666L, &session);
+    if (!status.isOk()) {
+        ASSERT_EQ(EX_UNSUPPORTED_OPERATION, status.getExceptionCode());
+        return;
+    }
+    ASSERT_NE(nullptr, session);
+    ASSERT_TRUE(session->pause().isOk());
+    ASSERT_TRUE(session->resume().isOk());
+    // Test normal destroy operation
+    ASSERT_TRUE(session->close().isOk());
+    session.reset();
+}
+TEST_P(PowerAidl, createHintSessionFailed) {
+    std::shared_ptr<IPowerHintSession> session;
+    auto status = power->createHintSession(getpid(), getuid(), kEmptyTids, 16666666L, &session);
+    ASSERT_FALSE(status.isOk());
+    if (EX_UNSUPPORTED_OPERATION == status.getExceptionCode()) {
+        return;
+    }
+    // Test with empty tid list
+    ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
+}
+
+TEST_P(PowerAidl, updateAndReportDurations) {
+    std::shared_ptr<IPowerHintSession> session;
+    auto status = power->createHintSession(getpid(), getuid(), kSelfTids, 16666666L, &session);
+    if (!status.isOk()) {
+        ASSERT_EQ(EX_UNSUPPORTED_OPERATION, status.getExceptionCode());
+        return;
+    }
+    ASSERT_NE(nullptr, session);
+
+    ASSERT_TRUE(session->updateTargetWorkDuration(16666667LL).isOk());
+    ASSERT_TRUE(session->reportActualWorkDuration(kDurations).isOk());
+}
+
 // FIXED_PERFORMANCE mode is required for all devices which ship on Android 11
 // or later
 TEST_P(PowerAidl, hasFixedPerformance) {
@@ -128,12 +211,16 @@
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PowerAidl);
 INSTANTIATE_TEST_SUITE_P(Power, PowerAidl,
-                         testing::ValuesIn(android::getAidlHalInstanceNames(IPower::descriptor)),
-                         android::PrintInstanceNameToString);
+                         testing::ValuesIn(::android::getAidlHalInstanceNames(IPower::descriptor)),
+                         ::android::PrintInstanceNameToString);
+
+}  // namespace
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
-    ProcessState::self()->setThreadPoolMaxThreadCount(1);
-    ProcessState::self()->startThreadPool();
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
     return RUN_ALL_TESTS();
 }
+
+}  // namespace aidl::android::hardware::power
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/power/stats/aidl/default/PowerStats.cpp b/power/stats/aidl/default/PowerStats.cpp
index 7cf591e..4b771a8 100644
--- a/power/stats/aidl/default/PowerStats.cpp
+++ b/power/stats/aidl/default/PowerStats.cpp
@@ -32,15 +32,19 @@
     }
 
     int32_t id = mPowerEntityInfos.size();
+    auto info = p->getInfo();
 
-    for (const auto& [entityName, states] : p->getInfo()) {
+    size_t index = mStateResidencyDataProviders.size();
+    mStateResidencyDataProviders.emplace_back(std::move(p));
+
+    for (const auto& [entityName, states] : info) {
         PowerEntity i = {
                 .id = id++,
                 .name = entityName,
                 .states = states,
         };
         mPowerEntityInfos.emplace_back(i);
-        mStateResidencyDataProviders.emplace_back(std::move(p));
+        mStateResidencyDataProviderIndex.emplace_back(index);
     }
 }
 
@@ -92,7 +96,8 @@
         // Check to see if we already have data for the given id
         std::string powerEntityName = mPowerEntityInfos[id].name;
         if (stateResidencies.find(powerEntityName) == stateResidencies.end()) {
-            mStateResidencyDataProviders[id]->getStateResidencies(&stateResidencies);
+            mStateResidencyDataProviders.at(mStateResidencyDataProviderIndex.at(id))
+                    ->getStateResidencies(&stateResidencies);
         }
 
         // Append results if we have them
diff --git a/power/stats/aidl/default/PowerStats.h b/power/stats/aidl/default/PowerStats.h
index f4c5e69..91d272d 100644
--- a/power/stats/aidl/default/PowerStats.h
+++ b/power/stats/aidl/default/PowerStats.h
@@ -73,6 +73,8 @@
   private:
     std::vector<std::unique_ptr<IStateResidencyDataProvider>> mStateResidencyDataProviders;
     std::vector<PowerEntity> mPowerEntityInfos;
+    /* Index that maps each power entity id to an entry in mStateResidencyDataProviders */
+    std::vector<size_t> mStateResidencyDataProviderIndex;
 
     std::vector<std::unique_ptr<IEnergyConsumer>> mEnergyConsumers;
     std::vector<EnergyConsumer> mEnergyConsumerInfos;
diff --git a/power/stats/aidl/vts/VtsHalPowerStatsTargetTest.cpp b/power/stats/aidl/vts/VtsHalPowerStatsTargetTest.cpp
index bed3fdf..c7ba96c 100644
--- a/power/stats/aidl/vts/VtsHalPowerStatsTargetTest.cpp
+++ b/power/stats/aidl/vts/VtsHalPowerStatsTargetTest.cpp
@@ -40,6 +40,12 @@
 
 using ndk::SpAIBinder;
 
+#define ASSERT_OK(a)                                     \
+    do {                                                 \
+        auto ret = a;                                    \
+        ASSERT_TRUE(ret.isOk()) << ret.getDescription(); \
+    } while (0)
+
 class PowerStatsAidl : public testing::TestWithParam<std::string> {
   public:
     virtual void SetUp() override {
@@ -108,7 +114,7 @@
 // Each PowerEntity must have a valid name
 TEST_P(PowerStatsAidl, ValidatePowerEntityNames) {
     std::vector<PowerEntity> infos;
-    ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk());
+    ASSERT_OK(powerstats->getPowerEntityInfo(&infos));
 
     for (auto info : infos) {
         testNameValid(info.name);
@@ -118,7 +124,7 @@
 // Each power entity must have a unique name
 TEST_P(PowerStatsAidl, ValidatePowerEntityUniqueNames) {
     std::vector<PowerEntity> entities;
-    ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk());
+    ASSERT_OK(powerstats->getPowerEntityInfo(&entities));
 
     testUnique(entities, &PowerEntity::name);
 }
@@ -126,7 +132,7 @@
 // Each PowerEntity must have a unique ID
 TEST_P(PowerStatsAidl, ValidatePowerEntityIds) {
     std::vector<PowerEntity> entities;
-    ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk());
+    ASSERT_OK(powerstats->getPowerEntityInfo(&entities));
 
     testUnique(entities, &PowerEntity::id);
 }
@@ -134,7 +140,7 @@
 // Each power entity must have at least one state
 TEST_P(PowerStatsAidl, ValidateStateSize) {
     std::vector<PowerEntity> entities;
-    ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk());
+    ASSERT_OK(powerstats->getPowerEntityInfo(&entities));
 
     for (auto entity : entities) {
         EXPECT_GT(entity.states.size(), 0);
@@ -144,7 +150,7 @@
 // Each state must have a valid name
 TEST_P(PowerStatsAidl, ValidateStateNames) {
     std::vector<PowerEntity> entities;
-    ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk());
+    ASSERT_OK(powerstats->getPowerEntityInfo(&entities));
 
     for (auto entity : entities) {
         for (auto state : entity.states) {
@@ -156,7 +162,7 @@
 // Each state must have a name that is unique to the given PowerEntity
 TEST_P(PowerStatsAidl, ValidateStateUniqueNames) {
     std::vector<PowerEntity> entities;
-    ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk());
+    ASSERT_OK(powerstats->getPowerEntityInfo(&entities));
 
     for (auto entity : entities) {
         testUnique(entity.states, &State::name);
@@ -166,7 +172,7 @@
 // Each state must have an ID that is unique to the given PowerEntity
 TEST_P(PowerStatsAidl, ValidateStateUniqueIds) {
     std::vector<PowerEntity> entities;
-    ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk());
+    ASSERT_OK(powerstats->getPowerEntityInfo(&entities));
 
     for (auto entity : entities) {
         testUnique(entity.states, &State::id);
@@ -176,16 +182,16 @@
 // State residency must return a valid status
 TEST_P(PowerStatsAidl, TestGetStateResidency) {
     std::vector<StateResidencyResult> results;
-    ASSERT_TRUE(powerstats->getStateResidency({}, &results).isOk());
+    ASSERT_OK(powerstats->getStateResidency({}, &results));
 }
 
 // State residency must return all results
 TEST_P(PowerStatsAidl, TestGetStateResidencyAllResults) {
     std::vector<PowerEntity> entities;
-    ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk());
+    ASSERT_OK(powerstats->getPowerEntityInfo(&entities));
 
     std::vector<StateResidencyResult> results;
-    ASSERT_TRUE(powerstats->getStateResidency({}, &results).isOk());
+    ASSERT_OK(powerstats->getStateResidency({}, &results));
 
     testMatching(entities, &PowerEntity::id, results, &StateResidencyResult::id);
 }
@@ -193,10 +199,10 @@
 // Each result must contain all state residencies
 TEST_P(PowerStatsAidl, TestGetStateResidencyAllStateResidencies) {
     std::vector<PowerEntity> entities;
-    ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk());
+    ASSERT_OK(powerstats->getPowerEntityInfo(&entities));
 
     std::vector<StateResidencyResult> results;
-    ASSERT_TRUE(powerstats->getStateResidency({}, &results).isOk());
+    ASSERT_OK(powerstats->getStateResidency({}, &results));
 
     for (auto entity : entities) {
         auto it = std::find_if(results.begin(), results.end(),
@@ -210,7 +216,7 @@
 // State residency must return results for each requested power entity
 TEST_P(PowerStatsAidl, TestGetStateResidencySelectedResults) {
     std::vector<PowerEntity> entities;
-    ASSERT_TRUE(powerstats->getPowerEntityInfo(&entities).isOk());
+    ASSERT_OK(powerstats->getPowerEntityInfo(&entities));
     if (entities.empty()) {
         return;
     }
@@ -222,7 +228,7 @@
     }
 
     std::vector<StateResidencyResult> selectedResults;
-    ASSERT_TRUE(powerstats->getStateResidency(selectedIds, &selectedResults).isOk());
+    ASSERT_OK(powerstats->getStateResidency(selectedIds, &selectedResults));
 
     testMatching(selectedEntities, &PowerEntity::id, selectedResults, &StateResidencyResult::id);
 }
@@ -230,15 +236,25 @@
 // Energy meter info must return a valid status
 TEST_P(PowerStatsAidl, TestGetEnergyMeterInfo) {
     std::vector<Channel> info;
-    ASSERT_TRUE(powerstats->getEnergyMeterInfo(&info).isOk());
+    ASSERT_OK(powerstats->getEnergyMeterInfo(&info));
 }
 
-// Each channel must have a valid name and subsystem
+// Each channel must have a valid name
 TEST_P(PowerStatsAidl, ValidateChannelNames) {
     std::vector<Channel> channels;
-    ASSERT_TRUE(powerstats->getEnergyMeterInfo(&channels).isOk());
+    ASSERT_OK(powerstats->getEnergyMeterInfo(&channels));
+
     for (auto channel : channels) {
         testNameValid(channel.name);
+    }
+}
+
+// Each channel must have a valid subsystem
+TEST_P(PowerStatsAidl, ValidateSubsystemNames) {
+    std::vector<Channel> channels;
+    ASSERT_OK(powerstats->getEnergyMeterInfo(&channels));
+
+    for (auto channel : channels) {
         testNameValid(channel.subsystem);
     }
 }
@@ -246,7 +262,7 @@
 // Each channel must have a unique name
 TEST_P(PowerStatsAidl, ValidateChannelUniqueNames) {
     std::vector<Channel> channels;
-    ASSERT_TRUE(powerstats->getEnergyMeterInfo(&channels).isOk());
+    ASSERT_OK(powerstats->getEnergyMeterInfo(&channels));
 
     testUnique(channels, &Channel::name);
 }
@@ -254,7 +270,7 @@
 // Each channel must have a unique ID
 TEST_P(PowerStatsAidl, ValidateChannelUniqueIds) {
     std::vector<Channel> channels;
-    ASSERT_TRUE(powerstats->getEnergyMeterInfo(&channels).isOk());
+    ASSERT_OK(powerstats->getEnergyMeterInfo(&channels));
 
     testUnique(channels, &Channel::id);
 }
@@ -262,16 +278,16 @@
 // Reading energy meter must return a valid status
 TEST_P(PowerStatsAidl, TestReadEnergyMeter) {
     std::vector<EnergyMeasurement> data;
-    ASSERT_TRUE(powerstats->readEnergyMeter({}, &data).isOk());
+    ASSERT_OK(powerstats->readEnergyMeter({}, &data));
 }
 
 // Reading energy meter must return results for all available channels
 TEST_P(PowerStatsAidl, TestGetAllEnergyMeasurements) {
     std::vector<Channel> channels;
-    ASSERT_TRUE(powerstats->getEnergyMeterInfo(&channels).isOk());
+    ASSERT_OK(powerstats->getEnergyMeterInfo(&channels));
 
     std::vector<EnergyMeasurement> measurements;
-    ASSERT_TRUE(powerstats->readEnergyMeter({}, &measurements).isOk());
+    ASSERT_OK(powerstats->readEnergyMeter({}, &measurements));
 
     testMatching(channels, &Channel::id, measurements, &EnergyMeasurement::id);
 }
@@ -279,7 +295,7 @@
 // Reading energy must must return results for each selected channel
 TEST_P(PowerStatsAidl, TestGetSelectedEnergyMeasurements) {
     std::vector<Channel> channels;
-    ASSERT_TRUE(powerstats->getEnergyMeterInfo(&channels).isOk());
+    ASSERT_OK(powerstats->getEnergyMeterInfo(&channels));
     if (channels.empty()) {
         return;
     }
@@ -291,7 +307,7 @@
     }
 
     std::vector<EnergyMeasurement> selectedMeasurements;
-    ASSERT_TRUE(powerstats->readEnergyMeter(selectedIds, &selectedMeasurements).isOk());
+    ASSERT_OK(powerstats->readEnergyMeter(selectedIds, &selectedMeasurements));
 
     testMatching(selectedChannels, &Channel::id, selectedMeasurements, &EnergyMeasurement::id);
 }
@@ -299,13 +315,13 @@
 // Energy consumer info must return a valid status
 TEST_P(PowerStatsAidl, TestGetEnergyConsumerInfo) {
     std::vector<EnergyConsumer> consumers;
-    ASSERT_TRUE(powerstats->getEnergyConsumerInfo(&consumers).isOk());
+    ASSERT_OK(powerstats->getEnergyConsumerInfo(&consumers));
 }
 
 // Each energy consumer must have a unique id
 TEST_P(PowerStatsAidl, TestGetEnergyConsumerUniqueId) {
     std::vector<EnergyConsumer> consumers;
-    ASSERT_TRUE(powerstats->getEnergyConsumerInfo(&consumers).isOk());
+    ASSERT_OK(powerstats->getEnergyConsumerInfo(&consumers));
 
     testUnique(consumers, &EnergyConsumer::id);
 }
@@ -313,7 +329,7 @@
 // Each energy consumer must have a valid name
 TEST_P(PowerStatsAidl, ValidateEnergyConsumerNames) {
     std::vector<EnergyConsumer> consumers;
-    ASSERT_TRUE(powerstats->getEnergyConsumerInfo(&consumers).isOk());
+    ASSERT_OK(powerstats->getEnergyConsumerInfo(&consumers));
 
     for (auto consumer : consumers) {
         testNameValid(consumer.name);
@@ -323,7 +339,7 @@
 // Each energy consumer must have a unique name
 TEST_P(PowerStatsAidl, ValidateEnergyConsumerUniqueNames) {
     std::vector<EnergyConsumer> consumers;
-    ASSERT_TRUE(powerstats->getEnergyConsumerInfo(&consumers).isOk());
+    ASSERT_OK(powerstats->getEnergyConsumerInfo(&consumers));
 
     testUnique(consumers, &EnergyConsumer::name);
 }
@@ -331,7 +347,7 @@
 // Energy consumers of the same type must have ordinals that are 0,1,2,..., N - 1
 TEST_P(PowerStatsAidl, ValidateEnergyConsumerOrdinals) {
     std::vector<EnergyConsumer> consumers;
-    ASSERT_TRUE(powerstats->getEnergyConsumerInfo(&consumers).isOk());
+    ASSERT_OK(powerstats->getEnergyConsumerInfo(&consumers));
 
     std::unordered_map<EnergyConsumerType, std::set<int32_t>> ordinalMap;
 
@@ -350,16 +366,16 @@
 // Energy consumed must return a valid status
 TEST_P(PowerStatsAidl, TestGetEnergyConsumed) {
     std::vector<EnergyConsumerResult> results;
-    ASSERT_TRUE(powerstats->getEnergyConsumed({}, &results).isOk());
+    ASSERT_OK(powerstats->getEnergyConsumed({}, &results));
 }
 
 // Energy consumed must return data for all energy consumers
 TEST_P(PowerStatsAidl, TestGetAllEnergyConsumed) {
     std::vector<EnergyConsumer> consumers;
-    ASSERT_TRUE(powerstats->getEnergyConsumerInfo(&consumers).isOk());
+    ASSERT_OK(powerstats->getEnergyConsumerInfo(&consumers));
 
     std::vector<EnergyConsumerResult> results;
-    ASSERT_TRUE(powerstats->getEnergyConsumed({}, &results).isOk());
+    ASSERT_OK(powerstats->getEnergyConsumed({}, &results));
 
     testMatching(consumers, &EnergyConsumer::id, results, &EnergyConsumerResult::id);
 }
@@ -367,7 +383,7 @@
 // Energy consumed must return data for each selected energy consumer
 TEST_P(PowerStatsAidl, TestGetSelectedEnergyConsumed) {
     std::vector<EnergyConsumer> consumers;
-    ASSERT_TRUE(powerstats->getEnergyConsumerInfo(&consumers).isOk());
+    ASSERT_OK(powerstats->getEnergyConsumerInfo(&consumers));
     if (consumers.empty()) {
         return;
     }
@@ -379,7 +395,7 @@
     }
 
     std::vector<EnergyConsumerResult> selectedResults;
-    ASSERT_TRUE(powerstats->getEnergyConsumed(selectedIds, &selectedResults).isOk());
+    ASSERT_OK(powerstats->getEnergyConsumed(selectedIds, &selectedResults));
 
     testMatching(selectedConsumers, &EnergyConsumer::id, selectedResults,
                  &EnergyConsumerResult::id);
@@ -388,7 +404,7 @@
 // Energy consumed attribution uids must be unique for a given energy consumer
 TEST_P(PowerStatsAidl, ValidateEnergyConsumerAttributionUniqueUids) {
     std::vector<EnergyConsumerResult> results;
-    ASSERT_TRUE(powerstats->getEnergyConsumed({}, &results).isOk());
+    ASSERT_OK(powerstats->getEnergyConsumed({}, &results));
 
     for (auto result : results) {
         testUnique(result.attribution, &EnergyConsumerAttribution::uid);
@@ -398,7 +414,7 @@
 // Energy consumed total energy >= sum total of uid-attributed energy
 TEST_P(PowerStatsAidl, TestGetEnergyConsumedAttributedEnergy) {
     std::vector<EnergyConsumerResult> results;
-    ASSERT_TRUE(powerstats->getEnergyConsumed({}, &results).isOk());
+    ASSERT_OK(powerstats->getEnergyConsumed({}, &results));
 
     for (auto result : results) {
         int64_t totalAttributedEnergyUWs = 0;
diff --git a/radio/1.6/IRadio.hal b/radio/1.6/IRadio.hal
index d201332..e2d35d0 100644
--- a/radio/1.6/IRadio.hal
+++ b/radio/1.6/IRadio.hal
@@ -145,7 +145,6 @@
      *
      * Response function is IRadioResponse.setupDataCallResponse_1_6()
      *
-     * Note this API is the same as the 1.5
      */
     oneway setupDataCall_1_6(int32_t serial, AccessNetwork accessNetwork,
             DataProfileInfo dataProfileInfo, bool roamingAllowed,
@@ -177,7 +176,7 @@
      * @param serial Serial number of request.
      * @param message GsmSmsMessage as defined in types.hal
      *
-     * Response function is IRadioResponse.sendSMSExpectMoreResponse_1_6()
+     * Response function is IRadioResponse.sendSmsExpectMoreResponse_1_6()
      *
      * Note this API is the same as the 1.0
      *
@@ -185,7 +184,7 @@
      * fails. RadioError:SMS_SEND_FAIL_RETRY means retry (i.e. error cause is 332)
      * and RadioError:GENERIC_FAILURE means no retry (i.e. error cause is 500)
      */
-    oneway sendSMSExpectMore_1_6(int32_t serial, GsmSmsMessage message);
+    oneway sendSmsExpectMore_1_6(int32_t serial, GsmSmsMessage message);
 
     /**
      * Send a CDMA SMS message
@@ -267,7 +266,7 @@
      * 2. Disable NR dual connectivity {NrDualConnectivityState:DISABLE}
      * 3. Disable NR dual connectivity and force secondary cell to be released
      * {NrDualConnectivityState:DISABLE_IMMEDIATE}
-
+     *
      * Response callback is IRadioResponse.setNRDualConnectivityStateResponse()
      */
     oneway setNrDualConnectivityState(int32_t serial,
@@ -372,7 +371,7 @@
      *
      * Response callback is IRadioResponse.getAllowedNetworkTypesBitmapResponse()
      */
-    oneway getAllowedNetworkTypesBitmap(uint32_t serial);
+    oneway getAllowedNetworkTypesBitmap(int32_t serial);
 
     /**
      * Control data throttling at modem.
@@ -544,4 +543,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..05a7585 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.
      *
@@ -106,11 +107,34 @@
     /**
      * Indicates physical channel configurations.
      *
-     * An empty configs list indicates that the radio is in idle mode.
+     * An empty configs list shall be returned when the radio is in idle mode (i.e. RRC idle).
      *
      * @param type Type of radio indication
      * @param configs Vector of PhysicalChannelConfigs
      */
     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..3ee46c2 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.
@@ -138,7 +139,7 @@
      *   RadioError:ACCESS_BARRED
      *   RadioError:BLOCKED_DUE_TO_CALL
      */
-    oneway sendSMSExpectMoreResponse_1_6(RadioResponseInfo info, SendSmsResult sms);
+    oneway sendSmsExpectMoreResponse_1_6(RadioResponseInfo info, SendSmsResult sms);
 
     /**
      * @param info Response info struct containing response type, serial no. and error
@@ -231,6 +232,7 @@
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
      *   RadioError:REQUEST_NOT_SUPPORTED
+     *   RadioError:INVALID_STATE
      */
     oneway setNrDualConnectivityStateResponse(RadioResponseInfo info);
 
@@ -433,7 +435,61 @@
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INTERNAL_ERR
      *   RadioError:MODEM_ERR
+     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     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 f2c0e76..d843fd8 100644
--- a/radio/1.6/types.hal
+++ b/radio/1.6/types.hal
@@ -55,9 +55,9 @@
 
 struct QosBandwidth {
     /** Maximum bit rate possible on the bearer */
-    int32_t maxBitrateKbps;
+    uint32_t maxBitrateKbps;
     /** Minimum bit rate that is guaranteed to be provided by the network */
-    int32_t guaranteedBitrateKbps;
+    uint32_t guaranteedBitrateKbps;
 };
 
 /** LTE/EPS Quality of Service parameters as per 3gpp spec 24.301 sec 9.9.4.3. */
@@ -106,7 +106,7 @@
 /**
  * Next header protocol numbers defined by IANA, RFC 5237
  */
-enum QosProtocol : int32_t {
+enum QosProtocol : int8_t {
     /** No protocol specified */
     UNSPECIFIED = -1,
     /** Transmission Control Protocol */
@@ -119,14 +119,14 @@
     AH = 51,
 };
 
-enum QosFilterDirection : int32_t {
+enum QosFilterDirection : int8_t {
     DOWNLINK = 0,
     UPLINK = 1,
     BIDIRECTIONAL = 2,
 };
 
 /** Allowed port numbers */
-enum QosPortRange : int32_t {
+enum QosPortRange : uint16_t {
     MIN = 20,
     MAX = 65535
 };
@@ -248,7 +248,7 @@
 };
 
 /** The allowed failure modes on an IWLAN handover failure. */
-enum HandoverFailureMode : int32_t {
+enum HandoverFailureMode : int8_t {
     /**
      * On data handover failure, fallback to the source data transport when the
      * fail cause is due to a hand off preference change.
@@ -379,7 +379,7 @@
 /**
  * NR Dual connectivity state
  */
-enum NrDualConnectivityState: int32_t {
+enum NrDualConnectivityState: int8_t {
     /**
      * Enable NR dual connectivity. Enabled state does not mean dual connectivity
      * is active. It means device is allowed to connect to both primary and secondary.
@@ -443,7 +443,7 @@
    uint32_t secondaryUplinkCapacityKbps;
 };
 
-enum DataThrottlingAction : int32_t {
+enum DataThrottlingAction : int8_t {
     /* Clear all existing data throttling. */
     NO_DATA_THROTTLING = 0,
 
@@ -581,9 +581,9 @@
      *
      * Reference: 3GPP TS 138.214 section 5.2.2.1.
      *
-     * Range [0, 15], INT_MAX means invalid/unreported.
+     * Range [0, 15], 0xFF means invalid/unreported.
      */
-    vec<uint32_t> csiCqiReport;
+    vec<uint8_t> csiCqiReport;
 };
 
 /**
@@ -740,22 +740,19 @@
 
         EutranRegistrationInfo eutranInfo;
 
-        struct NgranRegistrationInfo {
-            /**
-             * Network capabilities for voice over PS services. This info is valid only on NR
-             * network and must be present when the device is camped on NR. VopsInfo must be
-             * empty when the device is not camped on NR.
-             */
-            NrVopsInfo nrVopsInfo;
-        } ngranInfo;
+        /**
+         * Network capabilities for voice over PS services. This info is valid only on NR
+         * network and must be present when the device is camped on NR. VopsInfo must be
+         * empty when the device is not camped on NR.
+         */
+        NrVopsInfo ngranNrVopsInfo;
 
-        struct GeranRegistrationInfo {
-            /**
-             * True if the dual transfer mode is supported.
-             * Refer to 3GPP TS 44.108 section 3.4.25.3
-             */
-            bool dtmSupported;
-        } geranInfo;
+        /**
+         * True if the dual transfer mode is supported.
+         * Refer to 3GPP TS 44.108 section 3.4.25.3
+         */
+        bool geranDtmSupported;
+
     } accessTechnologySpecificInfo;
 };
 
@@ -874,10 +871,10 @@
     int32_t uplinkChannelNumber;
 
     /** Downlink cell bandwidth, in kHz */
-    int32_t cellBandwidthDownlink;
+    int32_t cellBandwidthDownlinkKhz;
 
     /** Uplink cell bandwidth, in kHz */
-    int32_t cellBandwidthUplink;
+    int32_t cellBandwidthUplinkKhz;
 
     /**
      * A list of data calls mapped to this physical channel. The context id must match the cid of
@@ -1059,7 +1056,7 @@
     SscMode value;
 };
 
-enum SliceStatus : int32_t {
+enum SliceStatus : int8_t {
     UNKNOWN,
     CONFIGURED, // Configured but not allowed or rejected yet
     ALLOWED,    // Allowed to be used
@@ -1072,7 +1069,7 @@
  * Enum representing session and service continuity mode as defined in
  * 3GPP TS 23.501.
  */
-enum SscMode : int32_t {
+enum SscMode : int8_t {
     MODE_1 = 1,
     MODE_2 = 2,
     MODE_3 = 3,
@@ -1081,7 +1078,7 @@
 /**
  * Public key type from carrier certificate.
  */
-enum PublicKeyType : int32_t {
+enum PublicKeyType : int8_t {
     EPDG    = 1,                   // Key type to be used for ePDG
     WLAN    = 2,                   // Key type to be used for WLAN
 };
@@ -1094,3 +1091,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 : int8_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..36eee10 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
@@ -158,6 +158,9 @@
                 {::android::hardware::radio::V1_6::RadioError::NONE,
                  ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
                  ::android::hardware::radio::V1_6::RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
+        if (radioRsp_v1_6->setupDataCallResult.trafficDescriptors.size() <= 0) {
+            return;
+        }
         EXPECT_EQ(optionalTrafficDescriptor.value().osAppId.value().osAppId,
                 radioRsp_v1_6->setupDataCallResult.trafficDescriptors[0].osAppId.value().osAppId);
     }
@@ -172,7 +175,18 @@
     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 (getRadioHalCapabilities()) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_v1_6->rspInfo.error,
+                {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
+    } else {
+        ASSERT_TRUE(
+                CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+                                 {::android::hardware::radio::V1_6::RadioError::NONE,
+                                  ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+                                  ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
+                                  ::android::hardware::radio::V1_6::RadioError::MODEM_ERR}));
+    }
 }
 
 /*
@@ -204,10 +218,10 @@
 }
 
 /*
- * Test IRadio_1_6.sendSMSExpectMore() for the response returned.
+ * Test IRadio_1_6.sendSmsExpectMore() for the response returned.
  */
-TEST_P(RadioHidlTest_v1_6, sendSMSExpectMore_1_6) {
-    LOG(DEBUG) << "sendSMSExpectMore";
+TEST_P(RadioHidlTest_v1_6, sendSmsExpectMore_1_6) {
+    LOG(DEBUG) << "sendSmsExpectMore";
     serial = GetRandomSerialNumber();
     GsmSmsMessage msg;
     msg.smscPdu = "";
@@ -227,7 +241,7 @@
              ::android::hardware::radio::V1_6::RadioError::SIM_ABSENT},
             CHECK_GENERAL_ERROR));
     }
-    LOG(DEBUG) << "sendSMSExpectMore finished";
+    LOG(DEBUG) << "sendSmsExpectMore finished";
 }
 
 /*
@@ -369,7 +383,7 @@
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
-    if (getRadioHalCapabilities().modemReducedFeatureSet1) {
+    if (getRadioHalCapabilities()) {
         ASSERT_TRUE(CheckAnyOfErrors(
                 radioRsp_v1_6->rspInfo.error,
                 {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
@@ -378,6 +392,7 @@
                 CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
                                  {::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
                                   ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
+                                  ::android::hardware::radio::V1_6::RadioError::INVALID_STATE,
                                   ::android::hardware::radio::V1_6::RadioError::NONE}));
     }
 }
@@ -394,7 +409,7 @@
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
-    if (getRadioHalCapabilities().modemReducedFeatureSet1) {
+    if (getRadioHalCapabilities()) {
         ASSERT_TRUE(CheckAnyOfErrors(
                 radioRsp_v1_6->rspInfo.error,
                 {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
@@ -420,7 +435,7 @@
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
-    if (getRadioHalCapabilities().modemReducedFeatureSet1) {
+    if (getRadioHalCapabilities()) {
         ASSERT_TRUE(CheckAnyOfErrors(
                 radioRsp_v1_6->rspInfo.error,
                 {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
@@ -440,7 +455,7 @@
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
-    if (getRadioHalCapabilities().modemReducedFeatureSet1) {
+    if (getRadioHalCapabilities()) {
         ASSERT_TRUE(CheckAnyOfErrors(
                 radioRsp_v1_6->rspInfo.error,
                 {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
@@ -460,7 +475,7 @@
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
-    if (getRadioHalCapabilities().modemReducedFeatureSet1) {
+    if (getRadioHalCapabilities()) {
         ASSERT_TRUE(CheckAnyOfErrors(
                 radioRsp_v1_6->rspInfo.error,
                 {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
@@ -479,7 +494,7 @@
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
-    if (getRadioHalCapabilities().modemReducedFeatureSet1) {
+    if (getRadioHalCapabilities()) {
         ASSERT_TRUE(CheckAnyOfErrors(
                 radioRsp_v1_6->rspInfo.error,
                 {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
@@ -727,8 +742,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 +752,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_P(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_test.cpp b/radio/1.6/vts/functional/radio_hidl_hal_test.cpp
index 6255f66..5d514a0 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_test.cpp
@@ -86,16 +86,14 @@
  * disabled.
  * <p/>
  * Typical usage within VTS:
- * if (getRadioHalCapabilities().modemReducedFeatureSet) return;
+ * if (getRadioHalCapabilities()) return;
  */
-HalDeviceCapabilities RadioHidlTest_v1_6::getRadioHalCapabilities() {
+bool RadioHidlTest_v1_6::getRadioHalCapabilities() {
     sp<::android::hardware::radio::config::V1_3::IRadioConfig> radioConfig_v1_3 =
             ::android::hardware::radio::config::V1_3::IRadioConfig::getService();
     if (radioConfig_v1_3.get() == nullptr) {
         // If v1_3 isn't present, the values are initialized to false
-        HalDeviceCapabilities radioHalCapabilities;
-        memset(&radioHalCapabilities, 0, sizeof(radioHalCapabilities));
-        return radioHalCapabilities;
+        return false;
     } else {
         // Get radioHalDeviceCapabilities from the radio config
         sp<RadioConfigResponse> radioConfigRsp = new (std::nothrow) RadioConfigResponse(*this);
@@ -104,6 +102,6 @@
 
         radioConfig_v1_3->getHalDeviceCapabilities(serial);
         EXPECT_EQ(std::cv_status::no_timeout, wait());
-        return radioConfigRsp->halDeviceCapabilities;
+        return radioConfigRsp->modemReducedFeatureSet1;
     }
 }
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..950d82a 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
@@ -38,14 +38,12 @@
 using namespace ::android::hardware::radio::V1_2;
 using namespace ::android::hardware::radio::V1_1;
 using namespace ::android::hardware::radio::V1_0;
-using namespace ::android::hardware::radio::config::V1_3;
 
 using ::android::sp;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
-using ::android::hardware::radio::config::V1_3::HalDeviceCapabilities;
 
 #define MODEM_EMERGENCY_CALL_ESTABLISH_TIME 3
 #define MODEM_EMERGENCY_CALL_DISCONNECT_TIME 3
@@ -103,6 +101,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(
@@ -757,7 +760,7 @@
             const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
             const SendSmsResult& sms);
 
-    Return<void> sendSMSExpectMoreResponse_1_6(
+    Return<void> sendSmsExpectMoreResponse_1_6(
             const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
             const SendSmsResult& sms);
 
@@ -829,6 +832,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 +1087,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.
@@ -1091,7 +1113,7 @@
   public:
     virtual void SetUp() override;
 
-    HalDeviceCapabilities getRadioHalCapabilities();
+    bool getRadioHalCapabilities();
 
     /* radio service handle */
     sp<::android::hardware::radio::V1_6::IRadio> radio_v1_6;
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..942964b 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();
 }
 
@@ -1086,7 +1090,7 @@
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::sendSMSExpectMoreResponse_1_6(
+Return<void> RadioResponse_v1_6::sendSmsExpectMoreResponse_1_6(
         const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
         const SendSmsResult& sms) {
     rspInfo = info;
@@ -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/radio/config/1.3/Android.bp b/radio/config/1.3/Android.bp
index cc5944d..dc0d82c 100644
--- a/radio/config/1.3/Android.bp
+++ b/radio/config/1.3/Android.bp
@@ -13,7 +13,6 @@
     name: "android.hardware.radio.config@1.3",
     root: "android.hardware",
     srcs: [
-        "types.hal",
         "IRadioConfig.hal",
         "IRadioConfigResponse.hal",
     ],
diff --git a/radio/config/1.3/IRadioConfigResponse.hal b/radio/config/1.3/IRadioConfigResponse.hal
index 863754f..15eefed 100644
--- a/radio/config/1.3/IRadioConfigResponse.hal
+++ b/radio/config/1.3/IRadioConfigResponse.hal
@@ -18,7 +18,6 @@
 
 import android.hardware.radio@1.6::RadioResponseInfo;
 import @1.2::IRadioConfigResponse;
-import HalDeviceCapabilities;
 
 /**
  * Interface declaring response functions to solicited radio config requests.
@@ -26,8 +25,18 @@
 interface IRadioConfigResponse extends @1.2::IRadioConfigResponse {
     /**
      * @param info Response info struct containing response type, serial no. and error
-     * @param capabilities Capabilities struct containing the capabilities of the
-     * device related to the Radio HAL
+     * @param modemReducedFeatureSet1 True indicates that the modem does NOT support the following
+     *        features.
+     *        - Providing either
+     *          android.hardware.radio@1.6::LinkCapacityEstimate:secondaryDownlinkCapacityKbps
+     *          or android.hardware.radio@1.6::LinkCapacityEstimate:secondaryUplinkCapacityKbps
+     *          when given from
+     *          android.hardware.radio@1.6::RadioIndication:currentLinkCapacityEstimate
+     *        - Calling android.hardware.radio@1.6::IRadio.setNrDualConnectivityState
+     *          or querying android.hardware.radio@1.6::IRadio.isNrDualConnectivityEnabled
+     *        - Requesting android.hardware.radio@1.6::IRadio.setDataThrottling()
+     *        - Providing android.hardware.radio@1.6::SlicingConfig through
+     *          android.hardware.radio@1.6::getSlicingConfig()
      *
      * Valid errors returned:
      *   RadioError:NONE
@@ -35,5 +44,5 @@
      *   RadioError:INTERNAL_ERR
      */
     oneway getHalDeviceCapabilitiesResponse(RadioResponseInfo info,
-        HalDeviceCapabilities capabilities);
+        bool modemReducedFeatureSet1);
 };
diff --git a/radio/config/1.3/types.hal b/radio/config/1.3/types.hal
deleted file mode 100644
index 2b6c9f0..0000000
--- a/radio/config/1.3/types.hal
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- */
-
-package android.hardware.radio.config@1.3;
-
-/**
- * Contains the device capabilities with respect to the Radio HAL.
- */
-struct HalDeviceCapabilities {
-  /**
-   * True indicates that the modem does NOT support the following features:
-   * <ul>
-   * <li>Providing either
-   * android.hardware.radio@1.6::LinkCapacityEstimate:secondaryDownlinkCapacityKbps
-   * or android.hardware.radio@1.6::LinkCapacityEstimate:secondaryUplinkCapacityKbps
-   * when given from android.hardware.radio@1.6::RadioIndication:currentLinkCapacityEstimate
-   * </li>
-   * <li> calling android.hardware.radio@1.6::IRadio.setNrDualConnectivityState
-   * or querying android.hardware.radio@1.6::IRadio.isNrDualConnectivityEnabled
-   * </li>
-   * <li>Requesting android.hardware.radio@1.6::IRadio.setDataThrottling()
-   * </li>
-   * </ul>
-   */
-  bool modemReducedFeatureSet1;
-};
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
index 895ae08..7235798 100644
--- a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
@@ -29,7 +29,6 @@
 #include <android/hardware/radio/config/1.2/types.h>
 #include <android/hardware/radio/config/1.3/IRadioConfig.h>
 #include <android/hardware/radio/config/1.3/IRadioConfigResponse.h>
-#include <android/hardware/radio/config/1.3/types.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
@@ -37,7 +36,7 @@
 
 #include "vts_test_util.h"
 
-using namespace ::android::hardware::radio::config::V1_2;
+using namespace ::android::hardware::radio::config::V1_3;
 
 using ::android::sp;
 using ::android::hardware::hidl_string;
@@ -46,9 +45,10 @@
 using ::android::hardware::Void;
 using ::android::hardware::radio::config::V1_1::ModemsConfig;
 using ::android::hardware::radio::config::V1_1::PhoneCapability;
+using ::android::hardware::radio::config::V1_2::IRadioConfigIndication;
 using ::android::hardware::radio::config::V1_2::SimSlotStatus;
-using ::android::hardware::radio::config::V1_3::HalDeviceCapabilities;
 using ::android::hardware::radio::config::V1_3::IRadioConfig;
+using ::android::hardware::radio::config::V1_3::IRadioConfigResponse;
 using ::android::hardware::radio::V1_0::RadioResponseInfo;
 
 #define RADIO_SERVICE_NAME "slot1"
@@ -63,7 +63,7 @@
   public:
     RadioResponseInfo rspInfo;
     PhoneCapability phoneCap;
-    HalDeviceCapabilities halDeviceCapabilities;
+    bool modemReducedFeatureSet1;
 
     RadioConfigResponse(RadioResponseWaiter& parent);
     virtual ~RadioConfigResponse() = default;
@@ -91,7 +91,7 @@
 
     Return<void> getHalDeviceCapabilitiesResponse(
             const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
-            const HalDeviceCapabilities& halDeviceCapabilities);
+            bool modemReducedFeatureSet1);
 };
 
 /* Callback class for radio config indication */
diff --git a/radio/config/1.3/vts/functional/radio_config_response.cpp b/radio/config/1.3/vts/functional/radio_config_response.cpp
index 11e3cce..6188733 100644
--- a/radio/config/1.3/vts/functional/radio_config_response.cpp
+++ b/radio/config/1.3/vts/functional/radio_config_response.cpp
@@ -64,8 +64,9 @@
 }
 
 Return<void> RadioConfigResponse::getHalDeviceCapabilitiesResponse(
-        const ::android::hardware::radio::V1_6::RadioResponseInfo& /* info */,
-        const ::android::hardware::radio::config::V1_3::HalDeviceCapabilities& capabilities) {
-    halDeviceCapabilities = capabilities;
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+        bool modemReducedFeatures) {
+    modemReducedFeatureSet1 = modemReducedFeatures;
+    parent.notify(info.serial);
     return Void();
 }
diff --git a/security/keymint/aidl/Android.bp b/security/keymint/aidl/Android.bp
index 6766d99..0c11f3b 100644
--- a/security/keymint/aidl/Android.bp
+++ b/security/keymint/aidl/Android.bp
@@ -26,6 +26,7 @@
             vndk: {
                 enabled: true,
             },
+            apps_enabled: false,
         },
         rust: {
             enabled: true,
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/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/DeviceInfo.aidl
similarity index 78%
copy from biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
copy to security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/DeviceInfo.aidl
index 4db47c9..d04d49c 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/DeviceInfo.aidl
@@ -31,21 +31,9 @@
 // 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.biometrics.face;
-@Backing(type="byte") @VintfStability
-enum SessionState {
-  IDLING = 0,
-  CLOSED = 1,
-  GENERATING_CHALLENGE = 2,
-  REVOKING_CHALLENGE = 3,
-  ENROLLING = 4,
-  AUTHENTICATING = 5,
-  DETECTING_INTERACTION = 6,
-  ENUMERATING_ENROLLMENTS = 7,
-  REMOVING_ENROLLMENTS = 8,
-  GETTING_FEATURES = 9,
-  SETTING_FEATURE = 10,
-  GETTING_AUTHENTICATOR_ID = 11,
-  INVALIDATING_AUTHENTICATOR_ID = 12,
-  RESETTING_LOCKOUT = 13,
+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/ErrorCode.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl
index 69ec4ce..b05a0f3 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl
@@ -118,6 +118,7 @@
   MISSING_ISSUER_SUBJECT = -82,
   INVALID_ISSUER_SUBJECT = -83,
   BOOT_LEVEL_EXCEEDED = -84,
+  HARDWARE_NOT_YET_AVAILABLE = -85,
   UNIMPLEMENTED = -100,
   VERSION_MISMATCH = -101,
   UNKNOWN_ERROR = -1000,
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..bf30999 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
@@ -33,7 +33,7 @@
 
 package android.hardware.security.keymint;
 /* @hide */
-@VintfStability
+@SensitiveData @VintfStability
 interface IKeyMintDevice {
   android.hardware.security.keymint.KeyMintHardwareInfo getHardwareInfo();
   void addRngEntropy(in byte[] data);
@@ -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/IKeyMintOperation.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintOperation.aidl
index 5ac2b4a..4ab4ffe 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintOperation.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintOperation.aidl
@@ -33,7 +33,7 @@
 
 package android.hardware.security.keymint;
 /* @hide */
-@VintfStability
+@SensitiveData @VintfStability
 interface IKeyMintOperation {
   void updateAad(in byte[] input, in @nullable android.hardware.security.keymint.HardwareAuthToken authToken, in @nullable android.hardware.security.secureclock.TimeStampToken timeStampToken);
   byte[] update(in byte[] input, in @nullable android.hardware.security.keymint.HardwareAuthToken authToken, in @nullable android.hardware.security.secureclock.TimeStampToken timeStampToken);
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..f566462 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
@@ -35,8 +35,9 @@
 /* @hide */
 @VintfStability
 interface IRemotelyProvisionedComponent {
+  android.hardware.security.keymint.RpcHardwareInfo getHardwareInfo();
   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/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SessionState.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
similarity index 79%
rename from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SessionState.aidl
rename to security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
index 9b0b6f6..06bce19 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SessionState.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
@@ -31,19 +31,14 @@
 // 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.biometrics.fingerprint;
-@Backing(type="byte") @VintfStability
-enum SessionState {
-  IDLING = 0,
-  CLOSED = 1,
-  GENERATING_CHALLENGE = 2,
-  REVOKING_CHALLENGE = 3,
-  ENROLLING = 4,
-  AUTHENTICATING = 5,
-  DETECTING_INTERACTION = 6,
-  ENUMERATING_ENROLLMENTS = 7,
-  REMOVING_ENROLLMENTS = 8,
-  GETTING_AUTHENTICATOR_ID = 9,
-  INVALIDATING_AUTHENTICATOR_ID = 10,
-  RESETTING_LOCKOUT = 11,
+package android.hardware.security.keymint;
+/* @hide */
+@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
+parcelable RpcHardwareInfo {
+  int versionNumber;
+  @utf8InCpp String rpcAuthorName;
+  int supportedEekCurve = 0;
+  const int CURVE_NONE = 0;
+  const int CURVE_P256 = 1;
+  const int CURVE_25519 = 2;
 }
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/ErrorCode.aidl b/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl
index 0e2c5f2..137e6b6 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl
@@ -107,6 +107,7 @@
     MISSING_ISSUER_SUBJECT = -82,
     INVALID_ISSUER_SUBJECT = -83,
     BOOT_LEVEL_EXCEEDED = -84,
+    HARDWARE_NOT_YET_AVAILABLE = -85,
 
     UNIMPLEMENTED = -100,
     VERSION_MISMATCH = -101,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 3100b23..1c503c2 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -214,6 +214,7 @@
  * @hide
  */
 @VintfStability
+@SensitiveData
 interface IKeyMintDevice {
     const int AUTH_TOKEN_MAC_LENGTH = 32;
 
@@ -321,8 +322,8 @@
      *        but `attestationKey` is non-null, the IKeyMintDevice must return
      *        ErrorCode::INVALID_ARGUMENT.  If the provided AttestationKey does not contain a key
      *        blob containing an asymmetric key with KeyPurpose::ATTEST_KEY, the IKeyMintDevice must
-     *        return ErrorCode::INVALID_PURPOSE.  If the provided AttestationKey has an empty issuer
-     *        subject name, the IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT.
+     *        return ErrorCode::INCOMPATIBLE_PURPOSE.  If the provided AttestationKey has an empty
+     *        issuer subject name, the IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT.
      *
      * @return The result of key creation.  See KeyCreationResult.aidl.
      */
@@ -360,8 +361,8 @@
      *        but `attestationKey` is non-null, the IKeyMintDevice must return
      *        ErrorCode::INVALID_ARGUMENT.  If the provided AttestationKey does not contain a key
      *        blob containing an asymmetric key with KeyPurpose::ATTEST_KEY, the IKeyMintDevice must
-     *        return ErrorCode::INVALID_PURPOSE.  If the provided AttestationKey has an empty issuer
-     *        subject name, the IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT.
+     *        return ErrorCode::INCOMPATIBLE_PURPOSE.  If the provided AttestationKey has an empty
+     *        issuer subject name, the IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT.
      *
      * @return The result of key creation.  See KeyCreationResult.aidl.
      */
@@ -762,6 +763,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/IKeyMintOperation.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
index 5ad54cd..d2a993f 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
@@ -22,6 +22,7 @@
 
 /** @hide */
 @VintfStability
+@SensitiveData
 interface IKeyMintOperation {
     /**
      * Provides additional authentication data (AAD) to a cryptographic operation begun with
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
index 5c8ca6d..b6285d9 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -16,8 +16,10 @@
 
 package android.hardware.security.keymint;
 
+import android.hardware.security.keymint.DeviceInfo;
 import android.hardware.security.keymint.MacedPublicKey;
 import android.hardware.security.keymint.ProtectedData;
+import android.hardware.security.keymint.RpcHardwareInfo;
 
 /**
  * An IRemotelyProvisionedComponent is a secure-side component for which certificates can be
@@ -120,6 +122,12 @@
     const int STATUS_INVALID_EEK = 5;
 
     /**
+     * @return info which contains information about the underlying IRemotelyProvisionedComponent
+     *         hardware, such as version number, component name, author name, and supported curve.
+     */
+    RpcHardwareInfo getHardwareInfo();
+
+    /**
      * generateKeyPair generates a new ECDSA P-256 key pair that can be certified.  Note that this
      * method only generates ECDSA P-256 key pairs, but the interface can be extended to add methods
      * for generating keys for other algorithms, if necessary.
@@ -201,7 +209,7 @@
      *                2 : bstr                        // KID : EEK ID
      *                3 : -25,                        // Algorithm : ECDH-ES + HKDF-256
      *                -1 : 4,                         // Curve : X25519
-     *                -2 : bstr                       // Ed25519 public key
+     *                -2 : bstr                       // X25519 public key
      *            }
      *
      *            EekSignatureInput = [
@@ -220,7 +228,7 @@
      *        in the chain, which implies that it must not attempt to validate the signature.
      *
      *        If testMode is false, the method must validate the chain signatures, and must verify
-     *        that the public key in the root certifictate is in its pre-configured set of
+     *        that the public key in the root certificate is in its pre-configured set of
      *        authorized EEK root keys. If the public key is not in the database, or if signature
      *        verification fails, the method must return STATUS_INVALID_EEK.
      *
@@ -257,7 +265,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..c2e21b6 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
@@ -53,13 +53,43 @@
 
     /**
      * 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.  Asymmetric key 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.  Tag::ATTESTATION_APPLICATION_ID must also be provided when the
+     *     ATTESTATION_CHALLENGE is provided, otherwise ATTESTATION_APPLICATION_ID_MISSING will be
+     *     returned.
+     *
+     * 2.  Asymmetric key 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.  Tag::
+     *     ATTESTATION_APPLICATION_ID must also be provided when the ATTESTATION_CHALLENGE is
+     *     provided, otherwise ATTESTATION_APPLICATION_ID_MISSING will be returned.
+     *
+     * 3.  Asymmetric key 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.  Tag::ATTESTATION_APPLICATION_ID will be ignored if provided.
+     *
+     * 4.  Asymmetric key 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.  Tag::ATTESTATION_APPLICATION_ID will be ignored if
+     *     provided.
+     *
+     * 5.  Symmetric key.  If the generated/imported key is symmetric, the certificate chain must
+     *     return empty, any Tag::ATTESTATION_CHALLENGE or Tag::ATTESTATION_APPLICATION_ID inputs,
+     *     if provided, are ignored.
      */
     Certificate[] certificateChain;
 }
diff --git a/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl b/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
index a26094c..62a48e9 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
@@ -26,7 +26,7 @@
     /**
      * key is a COSE_Mac0 structure containing the new public key.  It's MACed by a key available
      * only to the secure environment, as proof that the public key was generated by that
-     * environment. In CDDL, assuming the contained key is an Ed25519 public key:
+     * environment. In CDDL, assuming the contained key is a P-256 public key:
      *
      *     MacedPublicKey = [                     // COSE_Mac0
      *         protected: bstr .cbor { 1 : 5},    // Algorithm : HMAC-256
@@ -36,10 +36,11 @@
      *     ]
      *
      *     PublicKey = {               // COSE_Key
-     *         1 : 1,                  // Key type : octet key pair
-     *         3 : -8                  // Algorithm : EdDSA
-     *         -1 : 6,                 // Curve : Ed25519
+     *         1 : 2,                  // Key type : EC2
+     *         3 : -8                  // Algorithm : ES256
+     *         -1 : 6,                 // Curve : P256
      *         -2 : bstr               // X coordinate, little-endian
+     *         -3 : bstr               // Y coordinate, little-endian
      *         ? -70000 : nil          // Presence indicates this is a test key.  If set, K_mac is
      *                                 // all zeros.
      *     },
@@ -51,7 +52,7 @@
      *         payload : bstr .cbor PublicKey
      *     ]
      *
-     * if a non-Ed25519 public key were contained, the contents of the PublicKey map would change a
+     * if a non-P256 public key were contained, the contents of the PublicKey map would change a
      * little; see RFC 8152 for details.
      */
     byte[] macedKey;
diff --git a/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl b/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
index 44f316f..5199062 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
@@ -33,7 +33,7 @@
      *         unprotected: {
      *             5 : bstr .size 12       // IV
      *         },
-     *         ciphertext: bstr,           // AES-GCM-128(K, .cbor ProtectedDataPayload)
+     *         ciphertext: bstr,           // AES-GCM-256(K, .cbor ProtectedDataPayload)
      *         recipients : [
      *             [                       // COSE_Recipient
      *                 protected : bstr .cbor {
diff --git a/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
new file mode 100644
index 0000000..d297f87
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package android.hardware.security.keymint;
+
+/**
+ * RpcHardwareInfo is the hardware information returned by calling RemotelyProvisionedComponent
+ * getHardwareInfo()
+ * @hide
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable RpcHardwareInfo {
+    const int CURVE_NONE = 0;
+    const int CURVE_P256 = 1;
+    const int CURVE_25519 = 2;
+
+    /**
+     * Implementation version of the remotely provisioned component hardware.  The version number is
+     * implementation defined, and not necessarily globally meaningful.  The version is used to
+     * distinguish between different versions of a given implementation.
+     */
+    int versionNumber;
+
+    /**
+     * rpcAuthorName is the name of the author of the IRemotelyProvisionedComponent implementation
+     * (organization name, not individual). This name is implementation defined, so it can be used
+     * to distinguish between different implementations from the same author.
+     */
+    @utf8InCpp String rpcAuthorName;
+
+    /**
+     * supportedEekCurve returns an int representing which curve is supported for validating
+     * signatures over the Endpoint Encryption Key certificate chain and for using the corresponding
+     * signed encryption key in ECDH. Only one curve should be supported, with preference for 25519
+     * if it's available. These values are defined as constants above.
+     *
+     * CURVE_NONE is made the default to help ensure that an implementor doesn't accidentally forget
+     * to provide the correct information here, as the VTS tests will check to make certain that
+     * a passing implementation does not provide CURVE_NONE.
+     */
+    int supportedEekCurve = CURVE_NONE;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index 6243bb9..cde1fc0 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -249,8 +249,11 @@
     HARDWARE_TYPE = (1 << 28) /* TagType:ENUM */ | 304,
 
     /**
-     * Keys tagged with EARLY_BOOT_ONLY may only be used, or created, during early boot, until
-     * IKeyMintDevice::earlyBootEnded() is called.
+     * Keys tagged with EARLY_BOOT_ONLY may only be used during early boot, until
+     * IKeyMintDevice::earlyBootEnded() is called.  Early boot keys may be created after
+     * early boot.  Early boot keys may not be imprted at all, if Tag::EARLY_BOOT_ONLY is
+     * provided to IKeyMintDevice::importKey, the import must fail with
+     * ErrorCode::INVALID_ARGUMENT.
      */
     EARLY_BOOT_ONLY = (7 << 28) /* TagType:BOOL */ | 305,
 
diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp
index 63b91fe..230534c 100644
--- a/security/keymint/aidl/default/Android.bp
+++ b/security/keymint/aidl/default/Android.bp
@@ -33,35 +33,20 @@
         "libkeymint",
         "liblog",
         "libpuresoftkeymasterdevice",
-        "libremote_provisioner",
         "libutils",
     ],
     srcs: [
         "service.cpp",
     ],
+    required: [
+        "RemoteProvisioner",
+        "android.hardware.hardware_keystore.xml",
+    ],
 }
 
-cc_library {
-    name: "libremote_provisioner",
-    vendor_available: true,
-    static_libs: [
-        "libkeymint_remote_prov_support",
-    ],
-    shared_libs: [
-        "android.hardware.security.keymint-V1-ndk_platform",
-        "libbinder_ndk",
-        "libcppbor_external",
-        "libcppcose",
-        "libcrypto",
-        "libkeymaster_portable",
-        "libkeymint",
-        "liblog",
-        "libpuresoftkeymasterdevice",
-    ],
-    export_include_dirs: [
-        ".",
-    ],
-    srcs: [
-        "RemotelyProvisionedComponent.cpp",
-    ],
+prebuilt_etc {
+    name: "android.hardware.hardware_keystore.xml",
+    sub_dir: "permissions",
+    vendor: true,
+    src: "android.hardware.hardware_keystore.xml",
 }
diff --git a/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp b/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp
deleted file mode 100644
index 749f0bc..0000000
--- a/security/keymint/aidl/default/RemotelyProvisionedComponent.cpp
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * 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.
- */
-
-#include "RemotelyProvisionedComponent.h"
-
-#include <assert.h>
-#include <variant>
-
-#include <cppbor.h>
-#include <cppbor_parse.h>
-
-#include <KeyMintUtils.h>
-#include <cppcose/cppcose.h>
-#include <keymaster/keymaster_configuration.h>
-#include <remote_prov/remote_prov_utils.h>
-
-#include <openssl/bn.h>
-#include <openssl/ec.h>
-#include <openssl/rand.h>
-#include <openssl/x509.h>
-
-namespace aidl::android::hardware::security::keymint {
-
-using ::std::string;
-using ::std::tuple;
-using ::std::unique_ptr;
-using ::std::variant;
-using ::std::vector;
-using bytevec = ::std::vector<uint8_t>;
-
-using namespace cppcose;
-using namespace keymaster;
-
-namespace {
-
-constexpr auto STATUS_FAILED = RemotelyProvisionedComponent::STATUS_FAILED;
-constexpr auto STATUS_INVALID_EEK = RemotelyProvisionedComponent::STATUS_INVALID_EEK;
-constexpr auto STATUS_INVALID_MAC = RemotelyProvisionedComponent::STATUS_INVALID_MAC;
-constexpr uint32_t kAffinePointLength = 32;
-struct AStatusDeleter {
-    void operator()(AStatus* p) { AStatus_delete(p); }
-};
-
-// TODO(swillden): Remove the dependency on AStatus stuff.  The COSE lib should use something like
-// StatusOr, but it shouldn't depend on AStatus.
-class Status {
-  public:
-    Status() {}
-    Status(int32_t errCode, const std::string& errMsg)
-        : status_(AStatus_fromServiceSpecificErrorWithMessage(errCode, errMsg.c_str())) {}
-    explicit Status(const std::string& errMsg)
-        : status_(AStatus_fromServiceSpecificErrorWithMessage(STATUS_FAILED, errMsg.c_str())) {}
-    Status(AStatus* status) : status_(status) {}
-    Status(Status&&) = default;
-    Status(const Status&) = delete;
-
-    operator ::ndk::ScopedAStatus() && { return ndk::ScopedAStatus(status_.release()); }
-
-    bool isOk() { return !status_; }
-
-    // Don't call getMessage() unless isOk() returns false;
-    const char* getMessage() const { return AStatus_getMessage(status_.get()); }
-
-  private:
-    std::unique_ptr<AStatus, AStatusDeleter> status_;
-};
-
-template <typename T>
-class StatusOr {
-  public:
-    StatusOr(AStatus* status) : status_(status) {}
-    StatusOr(Status status) : status_(std::move(status)) {}
-    StatusOr(T val) : value_(std::move(val)) {}
-
-    bool isOk() { return status_.isOk(); }
-
-    T* operator->() & {
-        assert(isOk());
-        return &value_.value();
-    }
-    T& operator*() & {
-        assert(isOk());
-        return value_.value();
-    }
-    T&& operator*() && {
-        assert(isOk());
-        return std::move(value_).value();
-    }
-
-    const char* getMessage() const {
-        assert(!isOk());
-        return status_.getMessage();
-    }
-
-    Status moveError() {
-        assert(!isOk());
-        return std::move(status_);
-    }
-
-    T moveValue() { return std::move(value_).value(); }
-
-  private:
-    Status status_;
-    std::optional<T> value_;
-};
-
-StatusOr<std::pair<bytevec /* EEK pub */, bytevec /* EEK ID */>> validateAndExtractEekPubAndId(
-        bool testMode, const bytevec& endpointEncryptionCertChain) {
-    auto [item, newPos, errMsg] = cppbor::parse(endpointEncryptionCertChain);
-
-    if (!item || !item->asArray()) {
-        return Status("Error parsing EEK chain" + errMsg);
-    }
-
-    const cppbor::Array* certArr = item->asArray();
-    bytevec lastPubKey;
-    for (int i = 0; i < certArr->size(); ++i) {
-        auto cosePubKey = verifyAndParseCoseSign1(testMode, certArr->get(i)->asArray(),
-                                                  std::move(lastPubKey), bytevec{} /* AAD */);
-        if (!cosePubKey) {
-            return Status(STATUS_INVALID_EEK,
-                          "Failed to validate EEK chain: " + cosePubKey.moveMessage());
-        }
-        lastPubKey = *std::move(cosePubKey);
-    }
-
-    auto eek = CoseKey::parseX25519(lastPubKey, true /* requireKid */);
-    if (!eek) return Status(STATUS_INVALID_EEK, "Failed to get EEK: " + eek.moveMessage());
-
-    return std::make_pair(eek->getBstrValue(CoseKey::PUBKEY_X).value(),
-                          eek->getBstrValue(CoseKey::KEY_ID).value());
-}
-
-StatusOr<bytevec /* pubkeys */> validateAndExtractPubkeys(bool testMode,
-                                                          const vector<MacedPublicKey>& keysToSign,
-                                                          const bytevec& macKey) {
-    auto pubKeysToMac = cppbor::Array();
-    for (auto& keyToSign : keysToSign) {
-        auto [macedKeyItem, _, coseMacErrMsg] = cppbor::parse(keyToSign.macedKey);
-        if (!macedKeyItem || !macedKeyItem->asArray() ||
-            macedKeyItem->asArray()->size() != kCoseMac0EntryCount) {
-            return Status("Invalid COSE_Mac0 structure");
-        }
-
-        auto protectedParms = macedKeyItem->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
-        auto unprotectedParms = macedKeyItem->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
-        auto payload = macedKeyItem->asArray()->get(kCoseMac0Payload)->asBstr();
-        auto tag = macedKeyItem->asArray()->get(kCoseMac0Tag)->asBstr();
-        if (!protectedParms || !unprotectedParms || !payload || !tag) {
-            return Status("Invalid COSE_Mac0 contents");
-        }
-
-        auto [protectedMap, __, errMsg] = cppbor::parse(protectedParms);
-        if (!protectedMap || !protectedMap->asMap()) {
-            return Status("Invalid Mac0 protected: " + errMsg);
-        }
-        auto& algo = protectedMap->asMap()->get(ALGORITHM);
-        if (!algo || !algo->asInt() || algo->asInt()->value() != HMAC_256) {
-            return Status("Unsupported Mac0 algorithm");
-        }
-
-        auto pubKey = CoseKey::parse(payload->value(), EC2, ES256, P256);
-        if (!pubKey) return Status(pubKey.moveMessage());
-
-        bool testKey = static_cast<bool>(pubKey->getMap().get(CoseKey::TEST_KEY));
-        if (testMode && !testKey) {
-            return Status(BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST,
-                          "Production key in test request");
-        } else if (!testMode && testKey) {
-            return Status(BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST,
-                          "Test key in production request");
-        }
-
-        auto macTag = generateCoseMac0Mac(macKey, {} /* external_aad */, payload->value());
-        if (!macTag) return Status(STATUS_INVALID_MAC, macTag.moveMessage());
-        if (macTag->size() != tag->value().size() ||
-            CRYPTO_memcmp(macTag->data(), tag->value().data(), macTag->size()) != 0) {
-            return Status(STATUS_INVALID_MAC, "MAC tag mismatch");
-        }
-
-        pubKeysToMac.add(pubKey->moveMap());
-    }
-
-    return pubKeysToMac.encode();
-}
-
-StatusOr<std::pair<bytevec, bytevec>> buildCosePublicKeyFromKmCert(
-        const keymaster_blob_t* km_cert) {
-    if (km_cert == nullptr) {
-        return Status(STATUS_FAILED, "km_cert is a nullptr");
-    }
-    const uint8_t* temp = km_cert->data;
-    X509* cert = d2i_X509(NULL, &temp, km_cert->data_length);
-    if (cert == nullptr) {
-        return Status(STATUS_FAILED, "d2i_X509 returned null when attempting to get the cert.");
-    }
-    EVP_PKEY* pubKey = X509_get_pubkey(cert);
-    if (pubKey == nullptr) {
-        return Status(STATUS_FAILED, "Boringssl failed to get the public key from the cert");
-    }
-    EC_KEY* ecKey = EVP_PKEY_get0_EC_KEY(pubKey);
-    if (ecKey == nullptr) {
-        return Status(STATUS_FAILED,
-                      "The key in the certificate returned from GenerateKey is not "
-                      "an EC key.");
-    }
-    const EC_POINT* jacobian_coords = EC_KEY_get0_public_key(ecKey);
-    BIGNUM x;
-    BIGNUM y;
-    BN_CTX* ctx = BN_CTX_new();
-    if (ctx == nullptr) {
-        return Status(STATUS_FAILED, "Memory allocation failure for BN_CTX");
-    }
-    if (!EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ecKey), jacobian_coords, &x, &y,
-                                             ctx)) {
-        return Status(STATUS_FAILED, "Failed to get affine coordinates");
-    }
-    bytevec x_bytestring(kAffinePointLength);
-    bytevec y_bytestring(kAffinePointLength);
-    if (BN_bn2binpad(&x, x_bytestring.data(), kAffinePointLength) != kAffinePointLength) {
-        return Status(STATUS_FAILED, "Wrote incorrect number of bytes for x coordinate");
-    }
-    if (BN_bn2binpad(&y, y_bytestring.data(), kAffinePointLength) != kAffinePointLength) {
-        return Status(STATUS_FAILED, "Wrote incorrect number of bytes for y coordinate");
-    }
-    BN_CTX_free(ctx);
-    return std::make_pair(x_bytestring, y_bytestring);
-}
-
-cppbor::Array buildCertReqRecipients(const bytevec& pubkey, const bytevec& kid) {
-    return cppbor::Array()                   // Array of recipients
-            .add(cppbor::Array()             // Recipient
-                         .add(cppbor::Map()  // Protected
-                                      .add(ALGORITHM, ECDH_ES_HKDF_256)
-                                      .canonicalize()
-                                      .encode())
-                         .add(cppbor::Map()  // Unprotected
-                                      .add(COSE_KEY, cppbor::Map()
-                                                             .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
-                                                             .add(CoseKey::CURVE, cppcose::X25519)
-                                                             .add(CoseKey::PUBKEY_X, pubkey)
-                                                             .canonicalize())
-                                      .add(KEY_ID, kid)
-                                      .canonicalize())
-                         .add(cppbor::Null()));  // No ciphertext
-}
-
-static keymaster_key_param_t kKeyMintEcdsaP256Params[] = {
-        Authorization(TAG_PURPOSE, KM_PURPOSE_ATTEST_KEY),
-        Authorization(TAG_ALGORITHM, KM_ALGORITHM_EC), Authorization(TAG_KEY_SIZE, 256),
-        Authorization(TAG_DIGEST, KM_DIGEST_SHA_2_256),
-        Authorization(TAG_EC_CURVE, KM_EC_CURVE_P_256), Authorization(TAG_NO_AUTH_REQUIRED),
-        // The certificate generated by KM will be discarded, these values don't matter.
-        Authorization(TAG_CERTIFICATE_NOT_BEFORE, 0), Authorization(TAG_CERTIFICATE_NOT_AFTER, 0)};
-
-}  // namespace
-
-RemotelyProvisionedComponent::RemotelyProvisionedComponent(
-        std::shared_ptr<keymint::AndroidKeyMintDevice> keymint) {
-    std::tie(devicePrivKey_, bcc_) = generateBcc();
-    impl_ = keymint->getKeymasterImpl();
-}
-
-RemotelyProvisionedComponent::~RemotelyProvisionedComponent() {}
-
-ScopedAStatus RemotelyProvisionedComponent::generateEcdsaP256KeyPair(bool testMode,
-                                                                     MacedPublicKey* macedPublicKey,
-                                                                     bytevec* privateKeyHandle) {
-    // TODO(jbires): The following should move from ->GenerateKey to ->GenerateRKPKey and everything
-    //              after the GenerateKey call should basically be moved into that new function call
-    //              as well once the issue with libcppbor in system/keymaster is sorted out
-    GenerateKeyRequest request(impl_->message_version());
-    request.key_description.Reinitialize(kKeyMintEcdsaP256Params,
-                                         array_length(kKeyMintEcdsaP256Params));
-    GenerateKeyResponse response(impl_->message_version());
-    impl_->GenerateKey(request, &response);
-    if (response.error != KM_ERROR_OK) {
-        return km_utils::kmError2ScopedAStatus(response.error);
-    }
-
-    if (response.certificate_chain.entry_count != 1) {
-        // Error: Need the single non-signed certificate with the public key in it.
-        return Status(STATUS_FAILED,
-                      "Expected to receive a single certificate from GenerateKey. Instead got: " +
-                              std::to_string(response.certificate_chain.entry_count));
-    }
-    auto affineCoords = buildCosePublicKeyFromKmCert(response.certificate_chain.begin());
-    if (!affineCoords.isOk()) return affineCoords.moveError();
-    cppbor::Map cosePublicKeyMap = cppbor::Map()
-                                           .add(CoseKey::KEY_TYPE, EC2)
-                                           .add(CoseKey::ALGORITHM, ES256)
-                                           .add(CoseKey::CURVE, cppcose::P256)
-                                           .add(CoseKey::PUBKEY_X, affineCoords->first)
-                                           .add(CoseKey::PUBKEY_Y, affineCoords->second);
-    if (testMode) {
-        cosePublicKeyMap.add(CoseKey::TEST_KEY, cppbor::Null());
-    }
-
-    bytevec cosePublicKey = cosePublicKeyMap.canonicalize().encode();
-
-    auto macedKey = constructCoseMac0(testMode ? remote_prov::kTestMacKey : macKey_,
-                                      {} /* externalAad */, cosePublicKey);
-    if (!macedKey) return Status(macedKey.moveMessage());
-
-    macedPublicKey->macedKey = macedKey->encode();
-    *privateKeyHandle = km_utils::kmBlob2vector(response.key_blob);
-    return ScopedAStatus::ok();
-}
-
-ScopedAStatus RemotelyProvisionedComponent::generateCertificateRequest(
-        bool testMode, const vector<MacedPublicKey>& keysToSign,
-        const bytevec& endpointEncCertChain, const bytevec& challenge, bytevec* keysToSignMac,
-        ProtectedData* protectedData) {
-    auto pubKeysToSign = validateAndExtractPubkeys(testMode, keysToSign,
-                                                   testMode ? remote_prov::kTestMacKey : macKey_);
-    if (!pubKeysToSign.isOk()) return pubKeysToSign.moveError();
-
-    bytevec ephemeralMacKey = remote_prov::randomBytes(SHA256_DIGEST_LENGTH);
-
-    auto pubKeysToSignMac = generateCoseMac0Mac(ephemeralMacKey, bytevec{}, *pubKeysToSign);
-    if (!pubKeysToSignMac) return Status(pubKeysToSignMac.moveMessage());
-    *keysToSignMac = *std::move(pubKeysToSignMac);
-
-    bytevec devicePrivKey;
-    cppbor::Array bcc;
-    if (testMode) {
-        std::tie(devicePrivKey, bcc) = generateBcc();
-    } else {
-        devicePrivKey = devicePrivKey_;
-        bcc = bcc_.clone();
-    }
-
-    auto signedMac = constructCoseSign1(devicePrivKey /* Signing key */,  //
-                                        ephemeralMacKey /* Payload */,
-                                        cppbor::Array() /* AAD */
-                                                .add(challenge)
-                                                .add(createDeviceInfo())
-                                                .encode());
-    if (!signedMac) return Status(signedMac.moveMessage());
-
-    bytevec ephemeralPrivKey(X25519_PRIVATE_KEY_LEN);
-    bytevec ephemeralPubKey(X25519_PUBLIC_VALUE_LEN);
-    X25519_keypair(ephemeralPubKey.data(), ephemeralPrivKey.data());
-
-    auto eek = validateAndExtractEekPubAndId(testMode, endpointEncCertChain);
-    if (!eek.isOk()) return eek.moveError();
-
-    auto sessionKey = x25519_HKDF_DeriveKey(ephemeralPubKey, ephemeralPrivKey, eek->first,
-                                            true /* senderIsA */);
-    if (!sessionKey) return Status(sessionKey.moveMessage());
-
-    auto coseEncrypted =
-            constructCoseEncrypt(*sessionKey, remote_prov::randomBytes(kAesGcmNonceLength),
-                                 cppbor::Array()  // payload
-                                         .add(signedMac.moveValue())
-                                         .add(std::move(bcc))
-                                         .encode(),
-                                 {},  // aad
-                                 buildCertReqRecipients(ephemeralPubKey, eek->second));
-
-    if (!coseEncrypted) return Status(coseEncrypted.moveMessage());
-    protectedData->protectedData = coseEncrypted->encode();
-
-    return ScopedAStatus::ok();
-}
-
-bytevec RemotelyProvisionedComponent::deriveBytesFromHbk(const string& context,
-                                                         size_t numBytes) const {
-    bytevec fakeHbk(32, 0);
-    bytevec result(numBytes);
-
-    // TODO(swillden): Figure out if HKDF can fail.  It doesn't seem like it should be able to,
-    // but the function does return an error code.
-    HKDF(result.data(), numBytes,               //
-         EVP_sha256(),                          //
-         fakeHbk.data(), fakeHbk.size(),        //
-         nullptr /* salt */, 0 /* salt len */,  //
-         reinterpret_cast<const uint8_t*>(context.data()), context.size());
-
-    return result;
-}
-
-bytevec RemotelyProvisionedComponent::createDeviceInfo() const {
-    return cppbor::Map().encode();
-}
-
-std::pair<bytevec /* privKey */, cppbor::Array /* BCC */>
-RemotelyProvisionedComponent::generateBcc() {
-    bytevec privKey(ED25519_PRIVATE_KEY_LEN);
-    bytevec pubKey(ED25519_PUBLIC_KEY_LEN);
-
-    ED25519_keypair(pubKey.data(), privKey.data());
-
-    auto coseKey = cppbor::Map()
-                           .add(CoseKey::KEY_TYPE, OCTET_KEY_PAIR)
-                           .add(CoseKey::ALGORITHM, EDDSA)
-                           .add(CoseKey::CURVE, ED25519)
-                           .add(CoseKey::KEY_OPS, VERIFY)
-                           .add(CoseKey::PUBKEY_X, pubKey)
-                           .canonicalize()
-                           .encode();
-    auto sign1Payload = cppbor::Map()
-                                .add(1 /* Issuer */, "Issuer")
-                                .add(2 /* Subject */, "Subject")
-                                .add(-4670552 /* Subject Pub Key */, coseKey)
-                                .add(-4670553 /* Key Usage */,
-                                     std::vector<uint8_t>(0x05) /* Big endian order */)
-                                .canonicalize()
-                                .encode();
-    auto coseSign1 = constructCoseSign1(privKey,       /* signing key */
-                                        cppbor::Map(), /* extra protected */
-                                        sign1Payload, {} /* AAD */);
-    assert(coseSign1);
-
-    return {privKey, cppbor::Array().add(coseKey).add(coseSign1.moveValue())};
-}
-
-}  // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/aidl/default/RemotelyProvisionedComponent.h b/security/keymint/aidl/default/RemotelyProvisionedComponent.h
deleted file mode 100644
index e8d2343..0000000
--- a/security/keymint/aidl/default/RemotelyProvisionedComponent.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <AndroidKeyMintDevice.h>
-#include <aidl/android/hardware/security/keymint/BnRemotelyProvisionedComponent.h>
-#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
-#include <cppbor.h>
-#include <keymaster/UniquePtr.h>
-#include <keymaster/android_keymaster.h>
-
-namespace aidl::android::hardware::security::keymint {
-
-using ::ndk::ScopedAStatus;
-
-class RemotelyProvisionedComponent : public BnRemotelyProvisionedComponent {
-  public:
-    explicit RemotelyProvisionedComponent(std::shared_ptr<keymint::AndroidKeyMintDevice> keymint);
-    virtual ~RemotelyProvisionedComponent();
-
-    ScopedAStatus generateEcdsaP256KeyPair(bool testMode, MacedPublicKey* macedPublicKey,
-                                           std::vector<uint8_t>* privateKeyHandle) override;
-
-    ScopedAStatus generateCertificateRequest(bool testMode,
-                                             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;
-
-  private:
-    // TODO(swillden): Move these into an appropriate Context class.
-    std::vector<uint8_t> deriveBytesFromHbk(const std::string& context, size_t numBytes) const;
-    std::vector<uint8_t> createDeviceInfo() const;
-    std::pair<std::vector<uint8_t>, cppbor::Array> generateBcc();
-
-    std::vector<uint8_t> macKey_ = deriveBytesFromHbk("Key to MAC public keys", 32);
-    std::vector<uint8_t> devicePrivKey_;
-    cppbor::Array bcc_;
-    std::shared_ptr<::keymaster::AndroidKeymaster> impl_;
-};
-
-}  // namespace aidl::android::hardware::security::keymint
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/default/service.cpp b/security/keymint/aidl/default/service.cpp
index bcebbaf..8092e34 100644
--- a/security/keymint/aidl/default/service.cpp
+++ b/security/keymint/aidl/default/service.cpp
@@ -21,14 +21,13 @@
 #include <android/binder_process.h>
 
 #include <AndroidKeyMintDevice.h>
+#include <AndroidRemotelyProvisionedComponentDevice.h>
 #include <AndroidSecureClock.h>
 #include <AndroidSharedSecret.h>
 #include <keymaster/soft_keymaster_logger.h>
 
-#include "RemotelyProvisionedComponent.h"
-
 using aidl::android::hardware::security::keymint::AndroidKeyMintDevice;
-using aidl::android::hardware::security::keymint::RemotelyProvisionedComponent;
+using aidl::android::hardware::security::keymint::AndroidRemotelyProvisionedComponentDevice;
 using aidl::android::hardware::security::keymint::SecurityLevel;
 using aidl::android::hardware::security::secureclock::AndroidSecureClock;
 using aidl::android::hardware::security::sharedsecret::AndroidSharedSecret;
@@ -56,7 +55,7 @@
     // Add Shared Secret Service
     addService<AndroidSharedSecret>(keyMint);
     // Add Remotely Provisioned Component Service
-    addService<RemotelyProvisionedComponent>(keyMint);
+    addService<AndroidRemotelyProvisionedComponentDevice>(keyMint);
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reach
 }
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index 991d77a..6a92b8e 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -43,6 +43,8 @@
         "android.hardware.security.keymint-V1-ndk_platform",
         "android.hardware.security.secureclock-V1-ndk_platform",
         "libcppbor_external",
+        "libcppcose_rkp",
+        "libkeymint_remote_prov_support",
         "libkeymint_vts_test_utils",
     ],
     test_suites: [
@@ -73,6 +75,9 @@
         "android.hardware.security.keymint-V1-ndk_platform",
         "android.hardware.security.secureclock-V1-ndk_platform",
         "libcppbor_external",
+        "libcppcose_rkp",
+        "libgmock_ndk",
+        "libkeymint_remote_prov_support",
     ],
 }
 
@@ -87,18 +92,20 @@
     ],
     shared_libs: [
         "libbinder_ndk",
-        "libcppbor_external",
         "libcrypto",
-        "libkeymaster_portable",
-        "libpuresoftkeymasterdevice",
     ],
     static_libs: [
         "android.hardware.security.keymint-V1-ndk_platform",
-        "libcppcose",
+        "android.hardware.security.secureclock-V1-ndk_platform",
+        "libcppbor_external",
+        "libcppcose_rkp",
         "libgmock_ndk",
-        "libremote_provisioner",
+        "libkeymaster_portable",
         "libkeymint",
+        "libkeymint_support",
         "libkeymint_remote_prov_support",
+        "libkeymint_vts_test_utils",
+        "libpuresoftkeymasterdevice",
     ],
     test_suites: [
         "general-tests",
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index 7e7a466..daa3e18 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -26,29 +26,6 @@
 
 namespace {
 
-vector<uint8_t> make_name_from_str(const string& name) {
-    X509_NAME_Ptr x509_name(X509_NAME_new());
-    EXPECT_TRUE(x509_name.get() != nullptr);
-    if (!x509_name) return {};
-
-    EXPECT_EQ(1, X509_NAME_add_entry_by_txt(x509_name.get(),  //
-                                            "CN",             //
-                                            MBSTRING_ASC,
-                                            reinterpret_cast<const uint8_t*>(name.c_str()),
-                                            -1,  // len
-                                            -1,  // loc
-                                            0 /* set */));
-
-    int len = i2d_X509_NAME(x509_name.get(), nullptr /* only return length */);
-    EXPECT_GT(len, 0);
-
-    vector<uint8_t> retval(len);
-    uint8_t* p = retval.data();
-    i2d_X509_NAME(x509_name.get(), &p);
-
-    return retval;
-}
-
 bool IsSelfSigned(const vector<Certificate>& chain) {
     if (chain.size() != 1) return false;
     return ChainSignaturesAreValid(chain);
@@ -230,6 +207,36 @@
     }
 }
 
+TEST_P(AttestKeyTest, AttestWithNonAttestKey) {
+    // Create non-attestaton key.
+    AttestationKey non_attest_key;
+    vector<KeyCharacteristics> non_attest_key_characteristics;
+    vector<Certificate> non_attest_key_cert_chain;
+    ASSERT_EQ(
+            ErrorCode::OK,
+            GenerateKey(
+                    AuthorizationSetBuilder().EcdsaSigningKey(EcCurve::P_256).SetDefaultValidity(),
+                    {} /* attestation siging key */, &non_attest_key.keyBlob,
+                    &non_attest_key_characteristics, &non_attest_key_cert_chain));
+
+    EXPECT_EQ(non_attest_key_cert_chain.size(), 1);
+    EXPECT_TRUE(IsSelfSigned(non_attest_key_cert_chain));
+
+    // Attempt to sign attestation with non-attest key.
+    vector<uint8_t> attested_key_blob;
+    vector<KeyCharacteristics> attested_key_characteristics;
+    vector<Certificate> attested_key_cert_chain;
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+              GenerateKey(AuthorizationSetBuilder()
+                                  .EcdsaSigningKey(EcCurve::P_256)
+                                  .Authorization(TAG_NO_AUTH_REQUIRED)
+                                  .AttestationChallenge("foo")
+                                  .AttestationApplicationId("bar")
+                                  .SetDefaultValidity(),
+                          non_attest_key, &attested_key_blob, &attested_key_characteristics,
+                          &attested_key_cert_chain));
+}
+
 INSTANTIATE_KEYMINT_AIDL_TEST(AttestKeyTest);
 
 }  // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 3e87b6b..0dcc961 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -22,9 +22,13 @@
 
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
+#include <cppbor_parse.h>
 #include <cutils/properties.h>
+#include <gmock/gmock.h>
 #include <openssl/mem.h>
+#include <remote_prov/remote_prov_utils.h>
 
+#include <keymaster/cppcose/cppcose.h>
 #include <keymint_support/attestation_record.h>
 #include <keymint_support/key_param_output.h>
 #include <keymint_support/keymint_utils.h>
@@ -32,6 +36,7 @@
 
 namespace aidl::android::hardware::security::keymint {
 
+using namespace cppcose;
 using namespace std::literals::chrono_literals;
 using std::endl;
 using std::optional;
@@ -39,6 +44,7 @@
 using ::testing::AssertionFailure;
 using ::testing::AssertionResult;
 using ::testing::AssertionSuccess;
+using ::testing::MatchesRegex;
 
 ::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set) {
     if (set.size() == 0)
@@ -811,30 +817,6 @@
     return (found == key_characteristics.end()) ? kEmptyAuthList : found->authorizations;
 }
 
-AuthorizationSet KeyMintAidlTestBase::HwEnforcedAuthorizations(
-        const vector<KeyCharacteristics>& key_characteristics) {
-    AuthorizationSet authList;
-    for (auto& entry : key_characteristics) {
-        if (entry.securityLevel == SecurityLevel::STRONGBOX ||
-            entry.securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT) {
-            authList.push_back(AuthorizationSet(entry.authorizations));
-        }
-    }
-    return authList;
-}
-
-AuthorizationSet KeyMintAidlTestBase::SwEnforcedAuthorizations(
-        const vector<KeyCharacteristics>& key_characteristics) {
-    AuthorizationSet authList;
-    for (auto& entry : key_characteristics) {
-        if (entry.securityLevel == SecurityLevel::SOFTWARE ||
-            entry.securityLevel == SecurityLevel::KEYSTORE) {
-            authList.push_back(AuthorizationSet(entry.authorizations));
-        }
-    }
-    return authList;
-}
-
 ErrorCode KeyMintAidlTestBase::UseAesKey(const vector<uint8_t>& aesKeyBlob) {
     auto [result, ciphertext] = ProcessMessage(
             aesKeyBlob, KeyPurpose::ENCRYPT, "1234567890123456",
@@ -921,7 +903,7 @@
             if (att_hw_enforced[i].tag == TAG_BOOT_PATCHLEVEL ||
                 att_hw_enforced[i].tag == TAG_VENDOR_PATCHLEVEL) {
                 std::string date =
-                        std::to_string(att_hw_enforced[i].value.get<KeyParameterValue::dateTime>());
+                        std::to_string(att_hw_enforced[i].value.get<KeyParameterValue::integer>());
                 // strptime seems to require delimiters, but the tag value will
                 // be YYYYMMDD
                 date.insert(6, "-");
@@ -1046,6 +1028,28 @@
     return retval;
 }
 
+AuthorizationSet HwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics) {
+    AuthorizationSet authList;
+    for (auto& entry : key_characteristics) {
+        if (entry.securityLevel == SecurityLevel::STRONGBOX ||
+            entry.securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT) {
+            authList.push_back(AuthorizationSet(entry.authorizations));
+        }
+    }
+    return authList;
+}
+
+AuthorizationSet SwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics) {
+    AuthorizationSet authList;
+    for (auto& entry : key_characteristics) {
+        if (entry.securityLevel == SecurityLevel::SOFTWARE ||
+            entry.securityLevel == SecurityLevel::KEYSTORE) {
+            authList.push_back(AuthorizationSet(entry.authorizations));
+        }
+    }
+    return authList;
+}
+
 AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain) {
     std::stringstream cert_data;
 
@@ -1097,6 +1101,144 @@
     return X509_Ptr(d2i_X509(nullptr /* allocate new */, &p, blob.size()));
 }
 
+vector<uint8_t> make_name_from_str(const string& name) {
+    X509_NAME_Ptr x509_name(X509_NAME_new());
+    EXPECT_TRUE(x509_name.get() != nullptr);
+    if (!x509_name) return {};
+
+    EXPECT_EQ(1, X509_NAME_add_entry_by_txt(x509_name.get(),  //
+                                            "CN",             //
+                                            MBSTRING_ASC,
+                                            reinterpret_cast<const uint8_t*>(name.c_str()),
+                                            -1,  // len
+                                            -1,  // loc
+                                            0 /* set */));
+
+    int len = i2d_X509_NAME(x509_name.get(), nullptr /* only return length */);
+    EXPECT_GT(len, 0);
+
+    vector<uint8_t> retval(len);
+    uint8_t* p = retval.data();
+    i2d_X509_NAME(x509_name.get(), &p);
+
+    return retval;
+}
+
+namespace {
+
+void check_cose_key(const vector<uint8_t>& data, bool testMode) {
+    auto [parsedPayload, __, payloadParseErr] = cppbor::parse(data);
+    ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
+
+    // The following check assumes that canonical CBOR encoding is used for the COSE_Key.
+    if (testMode) {
+        EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
+                    MatchesRegex("{\n"
+                                 "  1 : 2,\n"   // kty: EC2
+                                 "  3 : -7,\n"  // alg: ES256
+                                 "  -1 : 1,\n"  // EC id: P256
+                                 // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
+                                 // sequence of 32 hexadecimal bytes, enclosed in braces and
+                                 // separated by commas. In this case, some Ed25519 public key.
+                                 "  -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"  // pub_x: data
+                                 "  -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"  // pub_y: data
+                                 "  -70000 : null,\n"                              // test marker
+                                 "}"));
+    } else {
+        EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
+                    MatchesRegex("{\n"
+                                 "  1 : 2,\n"   // kty: EC2
+                                 "  3 : -7,\n"  // alg: ES256
+                                 "  -1 : 1,\n"  // EC id: P256
+                                 // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
+                                 // sequence of 32 hexadecimal bytes, enclosed in braces and
+                                 // separated by commas. In this case, some Ed25519 public key.
+                                 "  -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"  // pub_x: data
+                                 "  -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"  // pub_y: data
+                                 "}"));
+    }
+}
+
+}  // namespace
+
+void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode,
+                        vector<uint8_t>* payload_value) {
+    auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
+    ASSERT_TRUE(coseMac0) << "COSE Mac0 parse failed " << mac0ParseErr;
+
+    ASSERT_NE(coseMac0->asArray(), nullptr);
+    ASSERT_EQ(coseMac0->asArray()->size(), kCoseMac0EntryCount);
+
+    auto protParms = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
+    ASSERT_NE(protParms, nullptr);
+
+    // Header label:value of 'alg': HMAC-256
+    ASSERT_EQ(cppbor::prettyPrint(protParms->value()), "{\n  1 : 5,\n}");
+
+    auto unprotParms = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
+    ASSERT_NE(unprotParms, nullptr);
+    ASSERT_EQ(unprotParms->size(), 0);
+
+    // The payload is a bstr holding an encoded COSE_Key
+    auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
+    ASSERT_NE(payload, nullptr);
+    check_cose_key(payload->value(), testMode);
+
+    auto coseMac0Tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
+    ASSERT_TRUE(coseMac0Tag);
+    auto extractedTag = coseMac0Tag->value();
+    EXPECT_EQ(extractedTag.size(), 32U);
+
+    // Compare with tag generated with kTestMacKey.  Should only match in test mode
+    auto testTag = cppcose::generateCoseMac0Mac(remote_prov::kTestMacKey, {} /* external_aad */,
+                                                payload->value());
+    ASSERT_TRUE(testTag) << "Tag calculation failed: " << testTag.message();
+
+    if (testMode) {
+        EXPECT_EQ(*testTag, extractedTag);
+    } else {
+        EXPECT_NE(*testTag, extractedTag);
+    }
+    if (payload_value != nullptr) {
+        *payload_value = payload->value();
+    }
+}
+
+void p256_pub_key(const vector<uint8_t>& coseKeyData, EVP_PKEY_Ptr* signingKey) {
+    // Extract x and y affine coordinates from the encoded Cose_Key.
+    auto [parsedPayload, __, payloadParseErr] = cppbor::parse(coseKeyData);
+    ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
+    auto coseKey = parsedPayload->asMap();
+    const std::unique_ptr<cppbor::Item>& xItem = coseKey->get(cppcose::CoseKey::PUBKEY_X);
+    ASSERT_NE(xItem->asBstr(), nullptr);
+    vector<uint8_t> x = xItem->asBstr()->value();
+    const std::unique_ptr<cppbor::Item>& yItem = coseKey->get(cppcose::CoseKey::PUBKEY_Y);
+    ASSERT_NE(yItem->asBstr(), nullptr);
+    vector<uint8_t> y = yItem->asBstr()->value();
+
+    // Concatenate: 0x04 (uncompressed form marker) | x | y
+    vector<uint8_t> pubKeyData{0x04};
+    pubKeyData.insert(pubKeyData.end(), x.begin(), x.end());
+    pubKeyData.insert(pubKeyData.end(), y.begin(), y.end());
+
+    EC_KEY_Ptr ecKey = EC_KEY_Ptr(EC_KEY_new());
+    ASSERT_NE(ecKey, nullptr);
+    EC_GROUP_Ptr group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+    ASSERT_NE(group, nullptr);
+    ASSERT_EQ(EC_KEY_set_group(ecKey.get(), group.get()), 1);
+    EC_POINT_Ptr point = EC_POINT_Ptr(EC_POINT_new(group.get()));
+    ASSERT_NE(point, nullptr);
+    ASSERT_EQ(EC_POINT_oct2point(group.get(), point.get(), pubKeyData.data(), pubKeyData.size(),
+                                 nullptr),
+              1);
+    ASSERT_EQ(EC_KEY_set_public_key(ecKey.get(), point.get()), 1);
+
+    EVP_PKEY_Ptr pubKey = EVP_PKEY_Ptr(EVP_PKEY_new());
+    ASSERT_NE(pubKey, nullptr);
+    EVP_PKEY_assign_EC_KEY(pubKey.get(), ecKey.release());
+    *signingKey = std::move(pubKey);
+}
+
 }  // namespace test
 
 }  // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 0aef81b..da174ce 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -25,6 +25,7 @@
 
 #include <aidl/android/hardware/security/keymint/ErrorCode.h>
 #include <aidl/android/hardware/security/keymint/IKeyMintDevice.h>
+#include <aidl/android/hardware/security/keymint/MacedPublicKey.h>
 
 #include <keymint_support/authorization_set.h>
 #include <keymint_support/openssl_utils.h>
@@ -252,10 +253,6 @@
     const vector<KeyParameter>& SecLevelAuthorizations(
             const vector<KeyCharacteristics>& key_characteristics, SecurityLevel securityLevel);
 
-    AuthorizationSet HwEnforcedAuthorizations(
-            const vector<KeyCharacteristics>& key_characteristics);
-    AuthorizationSet SwEnforcedAuthorizations(
-            const vector<KeyCharacteristics>& key_characteristics);
     ErrorCode UseAesKey(const vector<uint8_t>& aesKeyBlob);
     ErrorCode UseHmacKey(const vector<uint8_t>& hmacKeyBlob);
     ErrorCode UseRsaKey(const vector<uint8_t>& rsaKeyBlob);
@@ -280,12 +277,20 @@
                                const vector<uint8_t>& attestation_cert);
 string bin2hex(const vector<uint8_t>& data);
 X509_Ptr parse_cert_blob(const vector<uint8_t>& blob);
+vector<uint8_t> make_name_from_str(const string& name);
+void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode,
+                        vector<uint8_t>* payload_value);
+void p256_pub_key(const vector<uint8_t>& coseKeyData, EVP_PKEY_Ptr* signingKey);
+
+AuthorizationSet HwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
+AuthorizationSet SwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
 ::testing::AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain);
 
 #define INSTANTIATE_KEYMINT_AIDL_TEST(name)                                          \
     INSTANTIATE_TEST_SUITE_P(PerInstance, name,                                      \
                              testing::ValuesIn(KeyMintAidlTestBase::build_params()), \
-                             ::android::PrintInstanceNameToString)
+                             ::android::PrintInstanceNameToString);                  \
+    GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(name);
 
 }  // namespace test
 
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 7ecfa37..2d28845 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -27,6 +27,9 @@
 
 #include <cutils/properties.h>
 
+#include <android/binder_manager.h>
+
+#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
 #include <aidl/android/hardware/security/keymint/KeyFormat.h>
 
 #include <keymint_support/key_param_output.h>
@@ -134,6 +137,54 @@
                 "d5f33645e8ed8b4a1cb3cc4a1d67987399f2a09f5b3fb68c88d5e5d90ac3"
                 "3492d6");
 
+/*
+ * DER-encoded PKCS#8 format RSA key. Generated using:
+ *
+ * openssl genrsa 2048 | openssl pkcs8 -topk8 -nocrypt -outform der | hexdump -e '30/1  "%02X" "\n"'
+ */
+string rsa_2048_key =
+        hex2str("308204BD020100300D06092A864886F70D0101010500048204A7308204A3"
+                "0201000282010100BEBC342B56D443B1299F9A6A7056E80A897E318476A5"
+                "A18029E63B2ED739A61791D339F58DC763D9D14911F2EDEC383DEE11F631"
+                "9B44510E7A3ECD9B79B97382E49500ACF8117DC89CAF0E621F77756554A2"
+                "FD4664BFE7AB8B59AB48340DBFA27B93B5A81F6ECDEB02D0759307128DF3"
+                "E3BAD4055C8B840216DFAA5700670E6C5126F0962FCB70FF308F25049164"
+                "CCF76CC2DA66A7DD9A81A714C2809D69186133D29D84568E892B6FFBF319"
+                "9BDB14383EE224407F190358F111A949552ABA6714227D1BD7F6B20DD0CB"
+                "88F9467B719339F33BFF35B3870B3F62204E4286B0948EA348B524544B5F"
+                "9838F29EE643B079EEF8A713B220D7806924CDF7295070C5020301000102"
+                "82010069F377F35F2F584EF075353CCD1CA99738DB3DBC7C7FF35F9366CE"
+                "176DFD1B135AB10030344ABF5FBECF1D4659FDEF1C0FC430834BE1BE3911"
+                "951377BB3D563A2EA9CA8F4AD9C48A8CE6FD516A735C662686C7B4B3C09A"
+                "7B8354133E6F93F790D59EAEB92E84C9A4339302CCE28FDF04CCCAFA7DE3"
+                "F3A827D4F6F7D38E68B0EC6AB706645BF074A4E4090D06FB163124365FD5"
+                "EE7A20D350E9958CC30D91326E1B292E9EF5DB408EC42DAF737D20149704"
+                "D0A678A0FB5B5446863B099228A352D604BA8091A164D01D5AB05397C71E"
+                "AD20BE2A08FC528FE442817809C787FEE4AB97F97B9130D022153EDC6EB6"
+                "CBE7B0F8E3473F2E901209B5DB10F93604DB0102818100E83C0998214941"
+                "EA4F9293F1B77E2E99E6CF305FAF358238E126124FEAF2EB9724B2EA7B78"
+                "E6032343821A80E55D1D88FB12D220C3F41A56142FEC85796D1917F1E8C7"
+                "74F142B67D3D6E7B7E6B4383E94DB5929089DBB346D5BDAB40CC2D96EE04"
+                "09475E175C63BF78CFD744136740838127EA723FF3FE7FA368C1311B4A4E"
+                "0502818100D240FCC0F5D7715CDE21CB2DC86EA146132EA3B06F61FF2AF5"
+                "4BF38473F59DADCCE32B5F4CC32DD0BA6F509347B4B5B1B58C39F95E4798"
+                "CCBB43E83D0119ACF532F359CA743C85199F0286610E200997D731291717"
+                "9AC9B67558773212EC961E8BCE7A3CC809BC5486A96E4B0E6AF394D94E06"
+                "6A0900B7B70E82A44FB30053C102818100AD15DA1CBD6A492B66851BA8C3"
+                "16D38AB700E2CFDDD926A658003513C54BAA152B30021D667D20078F500F"
+                "8AD3E7F3945D74A891ED1A28EAD0FEEAEC8C14A8E834CF46A13D1378C99D"
+                "18940823CFDD27EC5810D59339E0C34198AC638E09C87CBB1B634A9864AE"
+                "9F4D5EB2D53514F67B4CAEC048C8AB849A02E397618F3271350281801FA2"
+                "C1A5331880A92D8F3E281C617108BF38244F16E352E69ED417C7153F9EC3"
+                "18F211839C643DCF8B4DD67CE2AC312E95178D5D952F06B1BF779F491692"
+                "4B70F582A23F11304E02A5E7565AE22A35E74FECC8B6FDC93F92A1A37703"
+                "E4CF0E63783BD02EB716A7ECBBFA606B10B74D01579522E7EF84D91FC522"
+                "292108D902C1028180796FE3825F9DCC85DF22D58690065D93898ACD65C0"
+                "87BEA8DA3A63BF4549B795E2CD0E3BE08CDEBD9FCF1720D9CDC5070D74F4"
+                "0DED8E1102C52152A31B6165F83A6722AECFCC35A493D7634664B888A08D"
+                "3EB034F12EA28BFEE346E205D334827F778B16ED40872BD29FCB36536B6E"
+                "93FFB06778696B4A9D81BB0A9423E63DE5");
+
 string ec_256_key =
         hex2str("308187020100301306072a8648ce3d020106082a8648ce3d030107046d30"
                 "6b0201010420737c2ecd7b8d1940bf2930aa9b4ed3ff941eed09366bc032"
@@ -209,6 +260,32 @@
     string to_string() const { return string(reinterpret_cast<const char*>(data()), size()); }
 };
 
+string device_suffix(const string& name) {
+    size_t pos = name.find('/');
+    if (pos == string::npos) {
+        return name;
+    }
+    return name.substr(pos + 1);
+}
+
+bool matching_rp_instance(const string& km_name,
+                          std::shared_ptr<IRemotelyProvisionedComponent>* rp) {
+    string km_suffix = device_suffix(km_name);
+
+    vector<string> rp_names =
+            ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor);
+    for (const string& rp_name : rp_names) {
+        // If the suffix of the RemotelyProvisionedComponent instance equals the suffix of the
+        // KeyMint instance, assume they match.
+        if (device_suffix(rp_name) == km_suffix && AServiceManager_isDeclared(rp_name.c_str())) {
+            ::ndk::SpAIBinder binder(AServiceManager_waitForService(rp_name.c_str()));
+            *rp = IRemotelyProvisionedComponent::fromBinder(binder);
+            return true;
+        }
+    }
+    return false;
+}
+
 }  // namespace
 
 class NewKeyGenerationTest : public KeyMintAidlTestBase {
@@ -322,6 +399,77 @@
 }
 
 /*
+ * NewKeyGenerationTest.RsaWithRpkAttestation
+ *
+ * Verifies that keymint can generate all required RSA key sizes, using an attestation key
+ * that has been generated using an associate IRemotelyProvisionedComponent.
+ */
+TEST_P(NewKeyGenerationTest, RsaWithRpkAttestation) {
+    // There should be an IRemotelyProvisionedComponent instance associated with the KeyMint
+    // instance.
+    std::shared_ptr<IRemotelyProvisionedComponent> rp;
+    ASSERT_TRUE(matching_rp_instance(GetParam(), &rp))
+            << "No IRemotelyProvisionedComponent found that matches KeyMint device " << GetParam();
+
+    // Generate a P-256 keypair to use as an attestation key.
+    MacedPublicKey macedPubKey;
+    std::vector<uint8_t> privateKeyBlob;
+    auto status =
+            rp->generateEcdsaP256KeyPair(/* testMode= */ false, &macedPubKey, &privateKeyBlob);
+    ASSERT_TRUE(status.isOk());
+    vector<uint8_t> coseKeyData;
+    check_maced_pubkey(macedPubKey, /* testMode= */ false, &coseKeyData);
+
+    AttestationKey attestation_key;
+    attestation_key.keyBlob = std::move(privateKeyBlob);
+    attestation_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+
+    for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
+        auto challenge = "hello";
+        auto app_id = "foo";
+
+        vector<uint8_t> key_blob;
+        vector<KeyCharacteristics> key_characteristics;
+        ASSERT_EQ(ErrorCode::OK,
+                  GenerateKey(AuthorizationSetBuilder()
+                                      .RsaSigningKey(key_size, 65537)
+                                      .Digest(Digest::NONE)
+                                      .Padding(PaddingMode::NONE)
+                                      .AttestationChallenge(challenge)
+                                      .AttestationApplicationId(app_id)
+                                      .Authorization(TAG_NO_AUTH_REQUIRED)
+                                      .SetDefaultValidity(),
+                              attestation_key, &key_blob, &key_characteristics, &cert_chain_));
+
+        ASSERT_GT(key_blob.size(), 0U);
+        CheckBaseParams(key_characteristics);
+
+        AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
+
+        EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA));
+        EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
+                << "Key size " << key_size << "missing";
+        EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
+
+        // Attestation by itself is not valid (last entry is not self-signed).
+        EXPECT_FALSE(ChainSignaturesAreValid(cert_chain_));
+
+        // The signature over the attested key should correspond to the P256 public key.
+        X509_Ptr key_cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+        ASSERT_TRUE(key_cert.get());
+        EVP_PKEY_Ptr signing_pubkey;
+        p256_pub_key(coseKeyData, &signing_pubkey);
+        ASSERT_TRUE(signing_pubkey.get());
+
+        ASSERT_TRUE(X509_verify(key_cert.get(), signing_pubkey.get()))
+                << "Verification of attested certificate failed "
+                << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
+
+        CheckedDeleteKey(&key_blob);
+    }
+}
+
+/*
  * NewKeyGenerationTest.LimitedUsageRsa
  *
  * Verifies that KeyMint can generate all required RSA key sizes with limited usage, and that the
@@ -1711,16 +1859,27 @@
  * Verifies that importing and using an RSA key pair works correctly.
  */
 TEST_P(ImportKeyTest, RsaSuccess) {
+    uint32_t key_size;
+    string key;
+
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        key_size = 2048;
+        key = rsa_2048_key;
+    } else {
+        key_size = 1024;
+        key = rsa_key;
+    }
+
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
                                                .Authorization(TAG_NO_AUTH_REQUIRED)
-                                               .RsaSigningKey(1024, 65537)
+                                               .RsaSigningKey(key_size, 65537)
                                                .Digest(Digest::SHA_2_256)
                                                .Padding(PaddingMode::RSA_PSS)
                                                .SetDefaultValidity(),
-                                       KeyFormat::PKCS8, rsa_key));
+                                       KeyFormat::PKCS8, key));
 
     CheckCryptoParam(TAG_ALGORITHM, Algorithm::RSA);
-    CheckCryptoParam(TAG_KEY_SIZE, 1024U);
+    CheckCryptoParam(TAG_KEY_SIZE, key_size);
     CheckCryptoParam(TAG_RSA_PUBLIC_EXPONENT, 65537U);
     CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
     CheckCryptoParam(TAG_PADDING, PaddingMode::RSA_PSS);
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 50e6cce..a2071c2 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -16,19 +16,22 @@
 
 #define LOG_TAG "VtsRemotelyProvisionableComponentTests"
 
-#include <RemotelyProvisionedComponent.h>
-#include <aidl/Gtest.h>
-#include <aidl/Vintf.h>
+#include <AndroidRemotelyProvisionedComponentDevice.h>
 #include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
 #include <aidl/android/hardware/security/keymint/SecurityLevel.h>
 #include <android/binder_manager.h>
 #include <cppbor_parse.h>
-#include <cppcose/cppcose.h>
 #include <gmock/gmock.h>
-#include <gtest/gtest.h>
+#include <keymaster/cppcose/cppcose.h>
 #include <keymaster/keymaster_configuration.h>
+#include <keymint_support/authorization_set.h>
+#include <openssl/ec.h>
+#include <openssl/ec_key.h>
+#include <openssl/x509.h>
 #include <remote_prov/remote_prov_utils.h>
 
+#include "KeyMintAidlTestBase.h"
+
 namespace aidl::android::hardware::security::keymint::test {
 
 using ::std::string;
@@ -52,6 +55,103 @@
     return bytevec(p, p + strlen(s));
 }
 
+ErrMsgOr<MacedPublicKey> corrupt_maced_key(const MacedPublicKey& macedPubKey) {
+    auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
+    if (!coseMac0 || coseMac0->asArray()->size() != kCoseMac0EntryCount) {
+        return "COSE Mac0 parse failed";
+    }
+    auto protParams = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
+    auto unprotParams = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
+    auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
+    auto tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
+    if (!protParams || !unprotParams || !payload || !tag) {
+        return "Invalid COSE_Sign1: missing content";
+    }
+    auto corruptMac0 = cppbor::Array();
+    corruptMac0.add(protParams->clone());
+    corruptMac0.add(unprotParams->clone());
+    corruptMac0.add(payload->clone());
+    vector<uint8_t> tagData = tag->value();
+    tagData[0] ^= 0x08;
+    tagData[tagData.size() - 1] ^= 0x80;
+    corruptMac0.add(cppbor::Bstr(tagData));
+
+    return MacedPublicKey{corruptMac0.encode()};
+}
+
+ErrMsgOr<cppbor::Array> corrupt_sig(const cppbor::Array* coseSign1) {
+    if (coseSign1->size() != kCoseSign1EntryCount) {
+        return "Invalid COSE_Sign1, wrong entry count";
+    }
+    const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
+    const cppbor::Map* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asMap();
+    const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
+    const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
+    if (!protectedParams || !unprotectedParams || !payload || !signature) {
+        return "Invalid COSE_Sign1: missing content";
+    }
+
+    auto corruptSig = cppbor::Array();
+    corruptSig.add(protectedParams->clone());
+    corruptSig.add(unprotectedParams->clone());
+    corruptSig.add(payload->clone());
+    vector<uint8_t> sigData = signature->value();
+    sigData[0] ^= 0x08;
+    corruptSig.add(cppbor::Bstr(sigData));
+
+    return std::move(corruptSig);
+}
+
+ErrMsgOr<EekChain> corrupt_sig_chain(const EekChain& eek, int which) {
+    auto [chain, _, parseErr] = cppbor::parse(eek.chain);
+    if (!chain || !chain->asArray()) {
+        return "EekChain parse failed";
+    }
+
+    cppbor::Array* eekChain = chain->asArray();
+    if (which >= eekChain->size()) {
+        return "selected sig out of range";
+    }
+    auto corruptChain = cppbor::Array();
+
+    for (int ii = 0; ii < eekChain->size(); ++ii) {
+        if (ii == which) {
+            auto sig = corrupt_sig(eekChain->get(which)->asArray());
+            if (!sig) {
+                return "Failed to build corrupted signature" + sig.moveMessage();
+            }
+            corruptChain.add(sig.moveValue());
+        } else {
+            corruptChain.add(eekChain->get(ii)->clone());
+        }
+    }
+    return EekChain{corruptChain.encode(), eek.last_pubkey, eek.last_privkey};
+}
+
+string device_suffix(const string& name) {
+    size_t pos = name.find('/');
+    if (pos == string::npos) {
+        return name;
+    }
+    return name.substr(pos + 1);
+}
+
+bool matching_keymint_device(const string& rp_name, std::shared_ptr<IKeyMintDevice>* keyMint) {
+    string rp_suffix = device_suffix(rp_name);
+
+    vector<string> km_names = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
+    for (const string& km_name : km_names) {
+        // If the suffix of the KeyMint instance equals the suffix of the
+        // RemotelyProvisionedComponent instance, assume they match.
+        if (device_suffix(km_name) == rp_suffix && AServiceManager_isDeclared(km_name.c_str())) {
+            ::ndk::SpAIBinder binder(AServiceManager_waitForService(km_name.c_str()));
+            *keyMint = IKeyMintDevice::fromBinder(binder);
+            return true;
+        }
+    }
+    return false;
+}
+
 }  // namespace
 
 class VtsRemotelyProvisionedComponentTests : public testing::TestWithParam<std::string> {
@@ -78,7 +178,8 @@
 INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests);
 
 /**
- * Generate and validate a production-mode key.  MAC tag can't be verified.
+ * Generate and validate a production-mode key.  MAC tag can't be verified, but
+ * the private key blob should be usable in KeyMint operations.
  */
 TEST_P(GenerateKeyTests, generateEcdsaP256Key_prodMode) {
     MacedPublicKey macedPubKey;
@@ -86,48 +187,72 @@
     bool testMode = false;
     auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
     ASSERT_TRUE(status.isOk());
+    vector<uint8_t> coseKeyData;
+    check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
+}
 
-    auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
-    ASSERT_TRUE(coseMac0) << "COSE Mac0 parse failed " << mac0ParseErr;
+/**
+ * Generate and validate a production-mode key, then use it as a KeyMint attestation key.
+ */
+TEST_P(GenerateKeyTests, generateAndUseEcdsaP256Key_prodMode) {
+    // See if there is a matching IKeyMintDevice for this IRemotelyProvisionedComponent.
+    std::shared_ptr<IKeyMintDevice> keyMint;
+    if (!matching_keymint_device(GetParam(), &keyMint)) {
+        // No matching IKeyMintDevice.
+        GTEST_SKIP() << "Skipping key use test as no matching KeyMint device found";
+        return;
+    }
+    KeyMintHardwareInfo info;
+    ASSERT_TRUE(keyMint->getHardwareInfo(&info).isOk());
 
-    ASSERT_NE(coseMac0->asArray(), nullptr);
-    ASSERT_EQ(coseMac0->asArray()->size(), kCoseMac0EntryCount);
+    MacedPublicKey macedPubKey;
+    bytevec privateKeyBlob;
+    bool testMode = false;
+    auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
+    ASSERT_TRUE(status.isOk());
+    vector<uint8_t> coseKeyData;
+    check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
 
-    auto protParms = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
-    ASSERT_NE(protParms, nullptr);
-    ASSERT_EQ(cppbor::prettyPrint(protParms->value()), "{\n  1 : 5,\n}");
+    AttestationKey attestKey;
+    attestKey.keyBlob = std::move(privateKeyBlob);
+    attestKey.issuerSubjectName = make_name_from_str("Android Keystore Key");
 
-    auto unprotParms = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
-    ASSERT_NE(unprotParms, nullptr);
-    ASSERT_EQ(unprotParms->size(), 0);
+    // Generate an ECDSA key that is attested by the generated P256 keypair.
+    AuthorizationSet keyDesc = AuthorizationSetBuilder()
+                                       .Authorization(TAG_NO_AUTH_REQUIRED)
+                                       .EcdsaSigningKey(256)
+                                       .AttestationChallenge("foo")
+                                       .AttestationApplicationId("bar")
+                                       .Digest(Digest::NONE)
+                                       .SetDefaultValidity();
+    KeyCreationResult creationResult;
+    auto result = keyMint->generateKey(keyDesc.vector_data(), attestKey, &creationResult);
+    ASSERT_TRUE(result.isOk());
+    vector<uint8_t> attested_key_blob = std::move(creationResult.keyBlob);
+    vector<KeyCharacteristics> attested_key_characteristics =
+            std::move(creationResult.keyCharacteristics);
+    vector<Certificate> attested_key_cert_chain = std::move(creationResult.certificateChain);
+    EXPECT_EQ(attested_key_cert_chain.size(), 1);
 
-    auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
-    ASSERT_NE(payload, nullptr);
-    auto [parsedPayload, __, payloadParseErr] = cppbor::parse(payload->value());
-    ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
-    EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
-                MatchesRegex("{\n"
-                             "  1 : 2,\n"
-                             "  3 : -7,\n"
-                             "  -1 : 1,\n"
-                             // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a sequence of
-                             // 32 hexadecimal bytes, enclosed in braces and separated by commas.
-                             // In this case, some Ed25519 public key.
-                             "  -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"
-                             "  -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"
-                             "}"));
+    AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+    AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+    EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced,
+                                          info.securityLevel,
+                                          attested_key_cert_chain[0].encodedCertificate));
 
-    auto coseMac0Tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
-    ASSERT_TRUE(coseMac0Tag);
-    auto extractedTag = coseMac0Tag->value();
-    EXPECT_EQ(extractedTag.size(), 32U);
+    // Attestation by itself is not valid (last entry is not self-signed).
+    EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
 
-    // Compare with tag generated with kTestMacKey.  Shouldn't match.
-    auto testTag = cppcose::generateCoseMac0Mac(remote_prov::kTestMacKey, {} /* external_aad */,
-                                                payload->value());
-    ASSERT_TRUE(testTag) << "Tag calculation failed: " << testTag.message();
+    // The signature over the attested key should correspond to the P256 public key.
+    X509_Ptr key_cert(parse_cert_blob(attested_key_cert_chain[0].encodedCertificate));
+    ASSERT_TRUE(key_cert.get());
+    EVP_PKEY_Ptr signing_pubkey;
+    p256_pub_key(coseKeyData, &signing_pubkey);
+    ASSERT_TRUE(signing_pubkey.get());
 
-    EXPECT_NE(*testTag, extractedTag);
+    ASSERT_TRUE(X509_verify(key_cert.get(), signing_pubkey.get()))
+            << "Verification of attested certificate failed "
+            << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
 }
 
 /**
@@ -140,56 +265,20 @@
     auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
     ASSERT_TRUE(status.isOk());
 
-    auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
-    ASSERT_TRUE(coseMac0) << "COSE Mac0 parse failed " << mac0ParseErr;
-
-    ASSERT_NE(coseMac0->asArray(), nullptr);
-    ASSERT_EQ(coseMac0->asArray()->size(), kCoseMac0EntryCount);
-
-    auto protParms = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
-    ASSERT_NE(protParms, nullptr);
-    ASSERT_EQ(cppbor::prettyPrint(protParms->value()), "{\n  1 : 5,\n}");
-
-    auto unprotParms = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
-    ASSERT_NE(unprotParms, nullptr);
-    ASSERT_EQ(unprotParms->size(), 0);
-
-    auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
-    ASSERT_NE(payload, nullptr);
-    auto [parsedPayload, __, payloadParseErr] = cppbor::parse(payload->value());
-    ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
-    EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
-                MatchesRegex("{\n"
-                             "  1 : 2,\n"
-                             "  3 : -7,\n"
-                             "  -1 : 1,\n"
-                             // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a sequence of
-                             // 32 hexadecimal bytes, enclosed in braces and separated by commas.
-                             // In this case, some Ed25519 public key.
-                             "  -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"
-                             "  -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n"
-                             "  -70000 : null,\n"
-                             "}"));
-
-    auto coseMac0Tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
-    ASSERT_TRUE(coseMac0);
-    auto extractedTag = coseMac0Tag->value();
-    EXPECT_EQ(extractedTag.size(), 32U);
-
-    // Compare with tag generated with kTestMacKey.  Should match.
-    auto testTag = cppcose::generateCoseMac0Mac(remote_prov::kTestMacKey, {} /* external_aad */,
-                                                payload->value());
-    ASSERT_TRUE(testTag) << testTag.message();
-
-    EXPECT_EQ(*testTag, extractedTag);
+    check_maced_pubkey(macedPubKey, testMode, nullptr);
 }
 
 class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
   protected:
-    CertificateRequestTest() : eekId_(string_to_bytevec("eekid")) {
-        auto chain = generateEekChain(3, eekId_);
+    CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(32)) {
+        generateEek(3);
+    }
+
+    void generateEek(size_t eekLength) {
+        auto chain = generateEekChain(eekLength, eekId_);
         EXPECT_TRUE(chain) << chain.message();
         if (chain) eekChain_ = chain.moveValue();
+        eekLength_ = eekLength;
     }
 
     void generateKeys(bool testMode, size_t numKeys) {
@@ -201,21 +290,76 @@
             auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &key, &privateKeyBlob);
             ASSERT_TRUE(status.isOk()) << status.getMessage();
 
-            auto [parsedMacedKey, _, parseErr] = cppbor::parse(key.macedKey);
-            ASSERT_TRUE(parsedMacedKey) << "Failed parsing MACed key: " << parseErr;
-            ASSERT_TRUE(parsedMacedKey->asArray()) << "COSE_Mac0 not an array?";
-            ASSERT_EQ(parsedMacedKey->asArray()->size(), kCoseMac0EntryCount);
-
-            auto& payload = parsedMacedKey->asArray()->get(kCoseMac0Payload);
-            ASSERT_TRUE(payload);
-            ASSERT_TRUE(payload->asBstr());
-
-            cborKeysToSign_.add(cppbor::EncodedItem(payload->asBstr()->value()));
+            vector<uint8_t> payload_value;
+            check_maced_pubkey(key, testMode, &payload_value);
+            cborKeysToSign_.add(cppbor::EncodedItem(payload_value));
         }
     }
 
+    void checkProtectedData(const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
+                            const bytevec& keysToSignMac, const ProtectedData& protectedData) {
+        auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
+        ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
+        ASSERT_TRUE(parsedProtectedData->asArray());
+        ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
+
+        auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
+        ASSERT_TRUE(senderPubkey) << senderPubkey.message();
+        EXPECT_EQ(senderPubkey->second, eekId_);
+
+        auto sessionKey = x25519_HKDF_DeriveKey(eekChain_.last_pubkey, eekChain_.last_privkey,
+                                                senderPubkey->first, false /* senderIsA */);
+        ASSERT_TRUE(sessionKey) << sessionKey.message();
+
+        auto protectedDataPayload =
+                decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
+        ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
+
+        auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
+        ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
+        ASSERT_TRUE(parsedPayload->asArray());
+        EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
+
+        auto& signedMac = parsedPayload->asArray()->get(0);
+        auto& bcc = parsedPayload->asArray()->get(1);
+        ASSERT_TRUE(signedMac && signedMac->asArray());
+        ASSERT_TRUE(bcc && bcc->asArray());
+
+        // BCC is [ pubkey, + BccEntry]
+        auto bccContents = validateBcc(bcc->asArray());
+        ASSERT_TRUE(bccContents) << "\n" << bccContents.message() << "\n" << prettyPrint(bcc.get());
+        ASSERT_GT(bccContents->size(), 0U);
+
+        auto [deviceInfoMap, __2, deviceInfoErrMsg] = cppbor::parse(deviceInfo.deviceInfo);
+        ASSERT_TRUE(deviceInfoMap) << "Failed to parse deviceInfo: " << deviceInfoErrMsg;
+        ASSERT_TRUE(deviceInfoMap->asMap());
+
+        auto& signingKey = bccContents->back().pubKey;
+        auto macKey = verifyAndParseCoseSign1(/* ignore_signature = */ false, signedMac->asArray(),
+                                              signingKey,
+                                              cppbor::Array()  // SignedMacAad
+                                                      .add(challenge_)
+                                                      .add(std::move(deviceInfoMap))
+                                                      .encode());
+        ASSERT_TRUE(macKey) << macKey.message();
+
+        auto coseMac0 = cppbor::Array()
+                                .add(cppbor::Map()  // protected
+                                             .add(ALGORITHM, HMAC_256)
+                                             .canonicalize()
+                                             .encode())
+                                .add(cppbor::Map())        // unprotected
+                                .add(keysToSign.encode())  // payload (keysToSign)
+                                .add(keysToSignMac);       // tag
+
+        auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
+        ASSERT_TRUE(macPayload) << macPayload.message();
+    }
+
     bytevec eekId_;
+    size_t eekLength_;
     EekChain eekChain_;
+    bytevec challenge_;
     std::vector<MacedPublicKey> keysToSign_;
     cppbor::Array cborKeysToSign_;
 };
@@ -226,65 +370,20 @@
  */
 TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
     bool testMode = true;
-    bytevec keysToSignMac;
-    ProtectedData protectedData;
-    auto challenge = randomBytes(32);
-    auto status = provisionable_->generateCertificateRequest(testMode, {} /* keysToSign */,
-                                                             eekChain_.chain, challenge,
-                                                             &keysToSignMac, &protectedData);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    for (size_t eekLength : {2, 3, 7}) {
+        SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
+        generateEek(eekLength);
 
-    auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
-    ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
-    ASSERT_TRUE(parsedProtectedData->asArray());
-    ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
+        bytevec keysToSignMac;
+        DeviceInfo deviceInfo;
+        ProtectedData protectedData;
+        auto status = provisionable_->generateCertificateRequest(
+                testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
+                &protectedData, &keysToSignMac);
+        ASSERT_TRUE(status.isOk()) << status.getMessage();
 
-    auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
-    ASSERT_TRUE(senderPubkey) << senderPubkey.message();
-    EXPECT_EQ(senderPubkey->second, eekId_);
-
-    auto sessionKey = x25519_HKDF_DeriveKey(eekChain_.last_pubkey, eekChain_.last_privkey,
-                                            senderPubkey->first, false /* senderIsA */);
-    ASSERT_TRUE(sessionKey) << sessionKey.message();
-
-    auto protectedDataPayload =
-            decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
-    ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
-
-    auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
-    ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
-    ASSERT_TRUE(parsedPayload->asArray());
-    EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
-
-    auto& signedMac = parsedPayload->asArray()->get(0);
-    auto& bcc = parsedPayload->asArray()->get(1);
-    ASSERT_TRUE(signedMac && signedMac->asArray());
-    ASSERT_TRUE(bcc && bcc->asArray());
-
-    // BCC is [ pubkey, + BccEntry]
-    auto bccContents = validateBcc(bcc->asArray());
-    ASSERT_TRUE(bccContents) << "\n" << bccContents.message() << "\n" << prettyPrint(bcc.get());
-    ASSERT_GT(bccContents->size(), 0U);
-
-    auto& signingKey = bccContents->back().pubKey;
-    auto macKey = verifyAndParseCoseSign1(testMode, signedMac->asArray(), signingKey,
-                                          cppbor::Array()          // DeviceInfo
-                                                  .add(challenge)  //
-                                                  .add(cppbor::Map())
-                                                  .encode());
-    ASSERT_TRUE(macKey) << macKey.message();
-
-    auto coseMac0 = cppbor::Array()
-                            .add(cppbor::Map()  // protected
-                                         .add(ALGORITHM, HMAC_256)
-                                         .canonicalize()
-                                         .encode())
-                            .add(cppbor::Map())              // unprotected
-                            .add(cppbor::Array().encode())   // payload (keysToSign)
-                            .add(std::move(keysToSignMac));  // tag
-
-    auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
-    ASSERT_TRUE(macPayload) << macPayload.message();
+        checkProtectedData(deviceInfo, cppbor::Array(), keysToSignMac, protectedData);
+    }
 }
 
 /**
@@ -296,14 +395,20 @@
  */
 TEST_P(CertificateRequestTest, EmptyRequest_prodMode) {
     bool testMode = false;
-    bytevec keysToSignMac;
-    ProtectedData protectedData;
-    auto challenge = randomBytes(32);
-    auto status = provisionable_->generateCertificateRequest(testMode, {} /* keysToSign */,
-                                                             eekChain_.chain, challenge,
-                                                             &keysToSignMac, &protectedData);
-    ASSERT_FALSE(status.isOk());
-    ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
+    for (size_t eekLength : {2, 3, 7}) {
+        SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
+        generateEek(eekLength);
+
+        bytevec keysToSignMac;
+        DeviceInfo deviceInfo;
+        ProtectedData protectedData;
+        auto status = provisionable_->generateCertificateRequest(
+                testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
+                &protectedData, &keysToSignMac);
+        EXPECT_FALSE(status.isOk());
+        EXPECT_EQ(status.getServiceSpecificError(),
+                  BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
+    }
 }
 
 /**
@@ -313,63 +418,20 @@
     bool testMode = true;
     generateKeys(testMode, 4 /* numKeys */);
 
-    bytevec keysToSignMac;
-    ProtectedData protectedData;
-    auto challenge = randomBytes(32);
-    auto status = provisionable_->generateCertificateRequest(
-            testMode, keysToSign_, eekChain_.chain, challenge, &keysToSignMac, &protectedData);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
+    for (size_t eekLength : {2, 3, 7}) {
+        SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
+        generateEek(eekLength);
 
-    auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
-    ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
-    ASSERT_TRUE(parsedProtectedData->asArray());
-    ASSERT_EQ(parsedProtectedData->asArray()->size(), kCoseEncryptEntryCount);
+        bytevec keysToSignMac;
+        DeviceInfo deviceInfo;
+        ProtectedData protectedData;
+        auto status = provisionable_->generateCertificateRequest(
+                testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
+                &keysToSignMac);
+        ASSERT_TRUE(status.isOk()) << status.getMessage();
 
-    auto senderPubkey = getSenderPubKeyFromCoseEncrypt(parsedProtectedData);
-    ASSERT_TRUE(senderPubkey) << senderPubkey.message();
-    EXPECT_EQ(senderPubkey->second, eekId_);
-
-    auto sessionKey = x25519_HKDF_DeriveKey(eekChain_.last_pubkey, eekChain_.last_privkey,
-                                            senderPubkey->first, false /* senderIsA */);
-    ASSERT_TRUE(sessionKey) << sessionKey.message();
-
-    auto protectedDataPayload =
-            decryptCoseEncrypt(*sessionKey, parsedProtectedData.get(), bytevec{} /* aad */);
-    ASSERT_TRUE(protectedDataPayload) << protectedDataPayload.message();
-
-    auto [parsedPayload, __, payloadErrMsg] = cppbor::parse(*protectedDataPayload);
-    ASSERT_TRUE(parsedPayload) << "Failed to parse payload: " << payloadErrMsg;
-    ASSERT_TRUE(parsedPayload->asArray());
-    EXPECT_EQ(parsedPayload->asArray()->size(), 2U);
-
-    auto& signedMac = parsedPayload->asArray()->get(0);
-    auto& bcc = parsedPayload->asArray()->get(1);
-    ASSERT_TRUE(signedMac && signedMac->asArray());
-    ASSERT_TRUE(bcc);
-
-    auto bccContents = validateBcc(bcc->asArray());
-    ASSERT_TRUE(bccContents) << "\n" << prettyPrint(bcc.get());
-    ASSERT_GT(bccContents->size(), 0U);
-
-    auto& signingKey = bccContents->back().pubKey;
-    auto macKey = verifyAndParseCoseSign1(testMode, signedMac->asArray(), signingKey,
-                                          cppbor::Array()          // DeviceInfo
-                                                  .add(challenge)  //
-                                                  .add(cppbor::Array())
-                                                  .encode());
-    ASSERT_TRUE(macKey) << macKey.message();
-
-    auto coseMac0 = cppbor::Array()
-                            .add(cppbor::Map()  // protected
-                                         .add(ALGORITHM, HMAC_256)
-                                         .canonicalize()
-                                         .encode())
-                            .add(cppbor::Map())              // unprotected
-                            .add(cborKeysToSign_.encode())   // payload
-                            .add(std::move(keysToSignMac));  // tag
-
-    auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
-    ASSERT_TRUE(macPayload) << macPayload.message();
+        checkProtectedData(deviceInfo, cborKeysToSign_, keysToSignMac, protectedData);
+    }
 }
 
 /**
@@ -383,11 +445,117 @@
     bool testMode = false;
     generateKeys(testMode, 4 /* numKeys */);
 
+    for (size_t eekLength : {2, 3, 7}) {
+        SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
+        generateEek(eekLength);
+
+        bytevec keysToSignMac;
+        DeviceInfo deviceInfo;
+        ProtectedData protectedData;
+        auto status = provisionable_->generateCertificateRequest(
+                testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
+                &keysToSignMac);
+        EXPECT_FALSE(status.isOk());
+        EXPECT_EQ(status.getServiceSpecificError(),
+                  BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
+    }
+}
+
+/**
+ * Generate a non-empty certificate request in test mode, but with the MAC corrupted on the keypair.
+ */
+TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_testMode) {
+    bool testMode = true;
+    generateKeys(testMode, 1 /* numKeys */);
+    MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
+
     bytevec keysToSignMac;
+    DeviceInfo deviceInfo;
     ProtectedData protectedData;
-    auto challenge = randomBytes(32);
     auto status = provisionable_->generateCertificateRequest(
-            testMode, keysToSign_, eekChain_.chain, challenge, &keysToSignMac, &protectedData);
+            testMode, {keyWithCorruptMac}, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
+            &keysToSignMac);
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
+}
+
+/**
+ * Generate a non-empty certificate request in prod mode, but with the MAC corrupted on the keypair.
+ */
+TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_prodMode) {
+    bool testMode = true;
+    generateKeys(testMode, 1 /* numKeys */);
+    MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
+
+    bytevec keysToSignMac;
+    DeviceInfo deviceInfo;
+    ProtectedData protectedData;
+    auto status = provisionable_->generateCertificateRequest(
+            testMode, {keyWithCorruptMac}, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
+            &keysToSignMac);
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    auto rc = status.getServiceSpecificError();
+
+    // TODO(drysdale): drop the INVALID_EEK potential error code when a real GEEK is available.
+    EXPECT_TRUE(rc == BnRemotelyProvisionedComponent::STATUS_INVALID_EEK ||
+                rc == BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
+}
+
+/**
+ * Generate a non-empty certificate request in prod mode that has a corrupt EEK chain.
+ * Confirm that the request is rejected.
+ *
+ * TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
+ * implementation is checking signatures.
+ */
+TEST_P(CertificateRequestTest, NonEmptyCorruptEekRequest_prodMode) {
+    bool testMode = false;
+    generateKeys(testMode, 4 /* numKeys */);
+
+    for (size_t ii = 0; ii < eekLength_; ii++) {
+        auto chain = corrupt_sig_chain(eekChain_, ii);
+        ASSERT_TRUE(chain) << chain.message();
+        EekChain corruptEek = chain.moveValue();
+
+        bytevec keysToSignMac;
+        DeviceInfo deviceInfo;
+        ProtectedData protectedData;
+        auto status = provisionable_->generateCertificateRequest(
+                testMode, keysToSign_, corruptEek.chain, challenge_, &deviceInfo, &protectedData,
+                &keysToSignMac);
+        ASSERT_FALSE(status.isOk());
+        ASSERT_EQ(status.getServiceSpecificError(),
+                  BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
+    }
+}
+
+/**
+ * Generate a non-empty certificate request in prod mode that has an incomplete EEK chain.
+ * Confirm that the request is rejected.
+ *
+ * TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
+ * implementation is checking signatures.
+ */
+TEST_P(CertificateRequestTest, NonEmptyIncompleteEekRequest_prodMode) {
+    bool testMode = false;
+    generateKeys(testMode, 4 /* numKeys */);
+
+    // Build an EEK chain that omits the first self-signed cert.
+    auto truncatedChain = cppbor::Array();
+    auto [chain, _, parseErr] = cppbor::parse(eekChain_.chain);
+    ASSERT_TRUE(chain);
+    auto eekChain = chain->asArray();
+    ASSERT_NE(eekChain, nullptr);
+    for (size_t ii = 1; ii < eekChain->size(); ii++) {
+        truncatedChain.add(eekChain->get(ii)->clone());
+    }
+
+    bytevec keysToSignMac;
+    DeviceInfo deviceInfo;
+    ProtectedData protectedData;
+    auto status = provisionable_->generateCertificateRequest(
+            testMode, keysToSign_, truncatedChain.encode(), challenge_, &deviceInfo, &protectedData,
+            &keysToSignMac);
     ASSERT_FALSE(status.isOk());
     ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
 }
@@ -400,11 +568,11 @@
     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 +586,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);
+            false /* testMode */, keysToSign_, eekChain_.chain, challenge_, &deviceInfo,
+            &protectedData, &keysToSignMac);
     ASSERT_FALSE(status.isOk());
     ASSERT_EQ(status.getServiceSpecificError(),
               BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
index fe04ede..718133a 100644
--- a/security/keymint/support/Android.bp
+++ b/security/keymint/support/Android.bp
@@ -57,29 +57,8 @@
         "include",
     ],
     shared_libs: [
-        "libcppcose",
         "libcppbor_external",
+        "libcppcose_rkp",
         "libcrypto",
     ],
 }
-
-cc_library {
-    name: "libcppcose",
-    vendor_available: true,
-    srcs: [
-        "cppcose.cpp",
-    ],
-    export_include_dirs: [
-        "include",
-    ],
-    shared_libs: [
-        "libbinder_ndk",
-        "libcppbor_external",
-        "libcrypto",
-        "liblog",
-    ],
-    static_libs: [
-        // TODO(swillden): Remove keymint NDK
-        "android.hardware.security.keymint-V1-ndk_platform",
-    ],
-}
diff --git a/security/keymint/support/cppcose.cpp b/security/keymint/support/cppcose.cpp
deleted file mode 100644
index bafb2b6..0000000
--- a/security/keymint/support/cppcose.cpp
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <cppcose/cppcose.h>
-
-#include <stdio.h>
-#include <iostream>
-
-#include <cppbor.h>
-#include <cppbor_parse.h>
-
-#include <openssl/err.h>
-
-namespace cppcose {
-
-namespace {
-
-ErrMsgOr<bssl::UniquePtr<EVP_CIPHER_CTX>> aesGcmInitAndProcessAad(const bytevec& key,
-                                                                  const bytevec& nonce,
-                                                                  const bytevec& aad,
-                                                                  bool encrypt) {
-    if (key.size() != kAesGcmKeySize) return "Invalid key size";
-
-    bssl::UniquePtr<EVP_CIPHER_CTX> ctx(EVP_CIPHER_CTX_new());
-    if (!ctx) return "Failed to allocate cipher context";
-
-    if (!EVP_CipherInit_ex(ctx.get(), EVP_aes_256_gcm(), nullptr /* engine */, key.data(),
-                           nonce.data(), encrypt ? 1 : 0)) {
-        return "Failed to initialize cipher";
-    }
-
-    int outlen;
-    if (!aad.empty() && !EVP_CipherUpdate(ctx.get(), nullptr /* out; null means AAD */, &outlen,
-                                          aad.data(), aad.size())) {
-        return "Failed to process AAD";
-    }
-
-    return std::move(ctx);
-}
-
-}  // namespace
-
-ErrMsgOr<bytevec> generateCoseMac0Mac(const bytevec& macKey, const bytevec& externalAad,
-                                      const bytevec& payload) {
-    auto macStructure = cppbor::Array()
-                                .add("MAC0")
-                                .add(cppbor::Map().add(ALGORITHM, HMAC_256).canonicalize().encode())
-                                .add(externalAad)
-                                .add(payload)
-                                .encode();
-
-    bytevec macTag(SHA256_DIGEST_LENGTH);
-    uint8_t* out = macTag.data();
-    unsigned int outLen;
-    out = HMAC(EVP_sha256(),                              //
-               macKey.data(), macKey.size(),              //
-               macStructure.data(), macStructure.size(),  //
-               out, &outLen);
-
-    assert(out != nullptr && outLen == macTag.size());
-    if (out == nullptr || outLen != macTag.size()) {
-        return "Error computing public key MAC";
-    }
-
-    return macTag;
-}
-
-ErrMsgOr<cppbor::Array> constructCoseMac0(const bytevec& macKey, const bytevec& externalAad,
-                                          const bytevec& payload) {
-    auto tag = generateCoseMac0Mac(macKey, externalAad, payload);
-    if (!tag) return tag.moveMessage();
-
-    return cppbor::Array()
-            .add(cppbor::Map().add(ALGORITHM, HMAC_256).canonicalize().encode())
-            .add(cppbor::Map() /* unprotected */)
-            .add(payload)
-            .add(tag.moveValue());
-}
-
-ErrMsgOr<bytevec /* payload */> parseCoseMac0(const cppbor::Item* macItem) {
-    auto mac = macItem ? macItem->asArray() : nullptr;
-    if (!mac || mac->size() != kCoseMac0EntryCount) {
-        return "Invalid COSE_Mac0";
-    }
-
-    auto protectedParms = mac->get(kCoseMac0ProtectedParams)->asBstr();
-    auto unprotectedParms = mac->get(kCoseMac0UnprotectedParams)->asMap();
-    auto payload = mac->get(kCoseMac0Payload)->asBstr();
-    auto tag = mac->get(kCoseMac0Tag)->asBstr();
-    if (!protectedParms || !unprotectedParms || !payload || !tag) {
-        return "Invalid COSE_Mac0 contents";
-    }
-
-    return payload->value();
-}
-
-ErrMsgOr<bytevec /* payload */> verifyAndParseCoseMac0(const cppbor::Item* macItem,
-                                                       const bytevec& macKey) {
-    auto mac = macItem ? macItem->asArray() : nullptr;
-    if (!mac || mac->size() != kCoseMac0EntryCount) {
-        return "Invalid COSE_Mac0";
-    }
-
-    auto protectedParms = mac->get(kCoseMac0ProtectedParams)->asBstr();
-    auto unprotectedParms = mac->get(kCoseMac0UnprotectedParams)->asMap();
-    auto payload = mac->get(kCoseMac0Payload)->asBstr();
-    auto tag = mac->get(kCoseMac0Tag)->asBstr();
-    if (!protectedParms || !unprotectedParms || !payload || !tag) {
-        return "Invalid COSE_Mac0 contents";
-    }
-
-    auto [protectedMap, _, errMsg] = cppbor::parse(protectedParms);
-    if (!protectedMap || !protectedMap->asMap()) {
-        return "Invalid Mac0 protected: " + errMsg;
-    }
-    auto& algo = protectedMap->asMap()->get(ALGORITHM);
-    if (!algo || !algo->asInt() || algo->asInt()->value() != HMAC_256) {
-        return "Unsupported Mac0 algorithm";
-    }
-
-    auto macTag = generateCoseMac0Mac(macKey, {} /* external_aad */, payload->value());
-    if (!macTag) return macTag.moveMessage();
-
-    if (macTag->size() != tag->value().size() ||
-        CRYPTO_memcmp(macTag->data(), tag->value().data(), macTag->size()) != 0) {
-        return "MAC tag mismatch";
-    }
-
-    return payload->value();
-}
-
-ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
-                                           const bytevec& payload, const bytevec& aad) {
-    bytevec signatureInput = cppbor::Array()
-                                     .add("Signature1")  //
-                                     .add(protectedParams)
-                                     .add(aad)
-                                     .add(payload)
-                                     .encode();
-
-    if (key.size() != ED25519_PRIVATE_KEY_LEN) return "Invalid signing key";
-    bytevec signature(ED25519_SIGNATURE_LEN);
-    if (!ED25519_sign(signature.data(), signatureInput.data(), signatureInput.size(), key.data())) {
-        return "Signing failed";
-    }
-
-    return signature;
-}
-
-ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, cppbor::Map protectedParams,
-                                           const bytevec& payload, const bytevec& aad) {
-    bytevec protParms = protectedParams.add(ALGORITHM, EDDSA).canonicalize().encode();
-    auto signature = createCoseSign1Signature(key, protParms, payload, aad);
-    if (!signature) return signature.moveMessage();
-
-    return cppbor::Array()
-            .add(protParms)
-            .add(cppbor::Map() /* unprotected parameters */)
-            .add(payload)
-            .add(*signature);
-}
-
-ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, const bytevec& payload,
-                                           const bytevec& aad) {
-    return constructCoseSign1(key, {} /* protectedParams */, payload, aad);
-}
-
-ErrMsgOr<bytevec> verifyAndParseCoseSign1(bool ignoreSignature, const cppbor::Array* coseSign1,
-                                          const bytevec& signingCoseKey, const bytevec& aad) {
-    if (!coseSign1 || coseSign1->size() != kCoseSign1EntryCount) {
-        return "Invalid COSE_Sign1";
-    }
-
-    const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
-    const cppbor::Map* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asMap();
-    const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
-    const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
-
-    if (!protectedParams || !unprotectedParams || !payload || !signature) {
-        return "Invalid COSE_Sign1";
-    }
-
-    auto [parsedProtParams, _, errMsg] = cppbor::parse(protectedParams);
-    if (!parsedProtParams) {
-        return errMsg + " when parsing protected params.";
-    }
-    if (!parsedProtParams->asMap()) {
-        return "Protected params must be a map";
-    }
-
-    auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
-    if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != EDDSA) {
-        return "Unsupported signature algorithm";
-    }
-
-    if (!ignoreSignature) {
-        bool selfSigned = signingCoseKey.empty();
-        auto key = CoseKey::parseEd25519(selfSigned ? payload->value() : signingCoseKey);
-        if (!key) return "Bad signing key: " + key.moveMessage();
-
-        bytevec signatureInput = cppbor::Array()
-                                         .add("Signature1")
-                                         .add(*protectedParams)
-                                         .add(aad)
-                                         .add(*payload)
-                                         .encode();
-
-        if (!ED25519_verify(signatureInput.data(), signatureInput.size(), signature->value().data(),
-                            key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
-            return "Signature verification failed";
-        }
-    }
-
-    return payload->value();
-}
-
-ErrMsgOr<bytevec> createCoseEncryptCiphertext(const bytevec& key, const bytevec& nonce,
-                                              const bytevec& protectedParams,
-                                              const bytevec& plaintextPayload, const bytevec& aad) {
-    auto ciphertext = aesGcmEncrypt(key, nonce,
-                                    cppbor::Array()                // Enc strucure as AAD
-                                            .add("Encrypt")        // Context
-                                            .add(protectedParams)  // Protected
-                                            .add(aad)              // External AAD
-                                            .encode(),
-                                    plaintextPayload);
-
-    if (!ciphertext) return ciphertext.moveMessage();
-    return ciphertext.moveValue();
-}
-
-ErrMsgOr<cppbor::Array> constructCoseEncrypt(const bytevec& key, const bytevec& nonce,
-                                             const bytevec& plaintextPayload, const bytevec& aad,
-                                             cppbor::Array recipients) {
-    auto encryptProtectedHeader = cppbor::Map()  //
-                                          .add(ALGORITHM, AES_GCM_256)
-                                          .canonicalize()
-                                          .encode();
-
-    auto ciphertext =
-            createCoseEncryptCiphertext(key, nonce, encryptProtectedHeader, plaintextPayload, aad);
-    if (!ciphertext) return ciphertext.moveMessage();
-
-    return cppbor::Array()
-            .add(encryptProtectedHeader)                       // Protected
-            .add(cppbor::Map().add(IV, nonce).canonicalize())  // Unprotected
-            .add(*ciphertext)                                  // Payload
-            .add(std::move(recipients));
-}
-
-ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>> getSenderPubKeyFromCoseEncrypt(
-        const cppbor::Item* coseEncrypt) {
-    if (!coseEncrypt || !coseEncrypt->asArray() ||
-        coseEncrypt->asArray()->size() != kCoseEncryptEntryCount) {
-        return "Invalid COSE_Encrypt";
-    }
-
-    auto& recipients = coseEncrypt->asArray()->get(kCoseEncryptRecipients);
-    if (!recipients || !recipients->asArray() || recipients->asArray()->size() != 1) {
-        return "Invalid recipients list";
-    }
-
-    auto& recipient = recipients->asArray()->get(0);
-    if (!recipient || !recipient->asArray() || recipient->asArray()->size() != 3) {
-        return "Invalid COSE_recipient";
-    }
-
-    auto& ciphertext = recipient->asArray()->get(2);
-    if (!ciphertext->asSimple() || !ciphertext->asSimple()->asNull()) {
-        return "Unexpected value in recipients ciphertext field " +
-               cppbor::prettyPrint(ciphertext.get());
-    }
-
-    auto& protParms = recipient->asArray()->get(0);
-    if (!protParms || !protParms->asBstr()) return "Invalid protected params";
-    auto [parsedProtParms, _, errMsg] = cppbor::parse(protParms->asBstr());
-    if (!parsedProtParms) return "Failed to parse protected params: " + errMsg;
-    if (!parsedProtParms->asMap()) return "Invalid protected params";
-
-    auto& algorithm = parsedProtParms->asMap()->get(ALGORITHM);
-    if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != ECDH_ES_HKDF_256) {
-        return "Invalid algorithm";
-    }
-
-    auto& unprotParms = recipient->asArray()->get(1);
-    if (!unprotParms || !unprotParms->asMap()) return "Invalid unprotected params";
-
-    auto& senderCoseKey = unprotParms->asMap()->get(COSE_KEY);
-    if (!senderCoseKey || !senderCoseKey->asMap()) return "Invalid sender COSE_Key";
-
-    auto& keyType = senderCoseKey->asMap()->get(CoseKey::KEY_TYPE);
-    if (!keyType || !keyType->asInt() || keyType->asInt()->value() != OCTET_KEY_PAIR) {
-        return "Invalid key type";
-    }
-
-    auto& curve = senderCoseKey->asMap()->get(CoseKey::CURVE);
-    if (!curve || !curve->asInt() || curve->asInt()->value() != X25519) {
-        return "Unsupported curve";
-    }
-
-    auto& pubkey = senderCoseKey->asMap()->get(CoseKey::PUBKEY_X);
-    if (!pubkey || !pubkey->asBstr() ||
-        pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) {
-        return "Invalid X25519 public key";
-    }
-
-    auto& key_id = unprotParms->asMap()->get(KEY_ID);
-    if (key_id && key_id->asBstr()) {
-        return std::make_pair(pubkey->asBstr()->value(), key_id->asBstr()->value());
-    }
-
-    // If no key ID, just return an empty vector.
-    return std::make_pair(pubkey->asBstr()->value(), bytevec{});
-}
-
-ErrMsgOr<bytevec> decryptCoseEncrypt(const bytevec& key, const cppbor::Item* coseEncrypt,
-                                     const bytevec& external_aad) {
-    if (!coseEncrypt || !coseEncrypt->asArray() ||
-        coseEncrypt->asArray()->size() != kCoseEncryptEntryCount) {
-        return "Invalid COSE_Encrypt";
-    }
-
-    auto& protParms = coseEncrypt->asArray()->get(kCoseEncryptProtectedParams);
-    auto& unprotParms = coseEncrypt->asArray()->get(kCoseEncryptUnprotectedParams);
-    auto& ciphertext = coseEncrypt->asArray()->get(kCoseEncryptPayload);
-    auto& recipients = coseEncrypt->asArray()->get(kCoseEncryptRecipients);
-
-    if (!protParms || !protParms->asBstr() || !unprotParms || !ciphertext || !recipients) {
-        return "Invalid COSE_Encrypt";
-    }
-
-    auto [parsedProtParams, _, errMsg] = cppbor::parse(protParms->asBstr()->value());
-    if (!parsedProtParams) {
-        return errMsg + " when parsing protected params.";
-    }
-    if (!parsedProtParams->asMap()) {
-        return "Protected params must be a map";
-    }
-
-    auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
-    if (!algorithm || !algorithm->asInt() || algorithm->asInt()->value() != AES_GCM_256) {
-        return "Unsupported encryption algorithm";
-    }
-
-    if (!unprotParms->asMap() || unprotParms->asMap()->size() != 1) {
-        return "Invalid unprotected params";
-    }
-
-    auto& nonce = unprotParms->asMap()->get(IV);
-    if (!nonce || !nonce->asBstr() || nonce->asBstr()->value().size() != kAesGcmNonceLength) {
-        return "Invalid nonce";
-    }
-
-    if (!ciphertext->asBstr()) return "Invalid ciphertext";
-
-    auto aad = cppbor::Array()                             // Enc strucure as AAD
-                       .add("Encrypt")                     // Context
-                       .add(protParms->asBstr()->value())  // Protected
-                       .add(external_aad)                  // External AAD
-                       .encode();
-
-    return aesGcmDecrypt(key, nonce->asBstr()->value(), aad, ciphertext->asBstr()->value());
-}
-
-ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA,
-                                        const bytevec& pubKeyB, bool senderIsA) {
-    bytevec rawSharedKey(X25519_SHARED_KEY_LEN);
-    if (!::X25519(rawSharedKey.data(), privKeyA.data(), pubKeyB.data())) {
-        return "ECDH operation failed";
-    }
-
-    bytevec kdfContext = cppbor::Array()
-                                 .add(AES_GCM_256)
-                                 .add(cppbor::Array()  // Sender Info
-                                              .add(cppbor::Bstr("client"))
-                                              .add(bytevec{} /* nonce */)
-                                              .add(senderIsA ? pubKeyA : pubKeyB))
-                                 .add(cppbor::Array()  // Recipient Info
-                                              .add(cppbor::Bstr("server"))
-                                              .add(bytevec{} /* nonce */)
-                                              .add(senderIsA ? pubKeyB : pubKeyA))
-                                 .add(cppbor::Array()           // SuppPubInfo
-                                              .add(128)         // output key length
-                                              .add(bytevec{}))  // protected
-                                 .encode();
-
-    bytevec retval(SHA256_DIGEST_LENGTH);
-    bytevec salt{};
-    if (!HKDF(retval.data(), retval.size(),              //
-              EVP_sha256(),                              //
-              rawSharedKey.data(), rawSharedKey.size(),  //
-              salt.data(), salt.size(),                  //
-              kdfContext.data(), kdfContext.size())) {
-        return "ECDH HKDF failed";
-    }
-
-    return retval;
-}
-
-ErrMsgOr<bytevec> aesGcmEncrypt(const bytevec& key, const bytevec& nonce, const bytevec& aad,
-                                const bytevec& plaintext) {
-    auto ctx = aesGcmInitAndProcessAad(key, nonce, aad, true /* encrypt */);
-    if (!ctx) return ctx.moveMessage();
-
-    bytevec ciphertext(plaintext.size() + kAesGcmTagSize);
-    int outlen;
-    if (!EVP_CipherUpdate(ctx->get(), ciphertext.data(), &outlen, plaintext.data(),
-                          plaintext.size())) {
-        return "Failed to encrypt plaintext";
-    }
-    assert(plaintext.size() == outlen);
-
-    if (!EVP_CipherFinal_ex(ctx->get(), ciphertext.data() + outlen, &outlen)) {
-        return "Failed to finalize encryption";
-    }
-    assert(outlen == 0);
-
-    if (!EVP_CIPHER_CTX_ctrl(ctx->get(), EVP_CTRL_GCM_GET_TAG, kAesGcmTagSize,
-                             ciphertext.data() + plaintext.size())) {
-        return "Failed to retrieve tag";
-    }
-
-    return ciphertext;
-}
-
-ErrMsgOr<bytevec> aesGcmDecrypt(const bytevec& key, const bytevec& nonce, const bytevec& aad,
-                                const bytevec& ciphertextWithTag) {
-    auto ctx = aesGcmInitAndProcessAad(key, nonce, aad, false /* encrypt */);
-    if (!ctx) return ctx.moveMessage();
-
-    if (ciphertextWithTag.size() < kAesGcmTagSize) return "Missing tag";
-
-    bytevec plaintext(ciphertextWithTag.size() - kAesGcmTagSize);
-    int outlen;
-    if (!EVP_CipherUpdate(ctx->get(), plaintext.data(), &outlen, ciphertextWithTag.data(),
-                          ciphertextWithTag.size() - kAesGcmTagSize)) {
-        return "Failed to decrypt plaintext";
-    }
-    assert(plaintext.size() == outlen);
-
-    bytevec tag(ciphertextWithTag.end() - kAesGcmTagSize, ciphertextWithTag.end());
-    if (!EVP_CIPHER_CTX_ctrl(ctx->get(), EVP_CTRL_GCM_SET_TAG, kAesGcmTagSize, tag.data())) {
-        return "Failed to set tag: " + std::to_string(ERR_peek_last_error());
-    }
-
-    if (!EVP_CipherFinal_ex(ctx->get(), nullptr, &outlen)) {
-        return "Failed to finalize encryption";
-    }
-    assert(outlen == 0);
-
-    return plaintext;
-}
-
-}  // namespace cppcose
diff --git a/security/keymint/support/include/cppcose/cppcose.h b/security/keymint/support/include/cppcose/cppcose.h
deleted file mode 100644
index a936bfd..0000000
--- a/security/keymint/support/include/cppcose/cppcose.h
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <memory>
-#include <optional>
-#include <string>
-#include <vector>
-
-#include <cppbor.h>
-#include <cppbor_parse.h>
-
-#include <openssl/cipher.h>
-#include <openssl/curve25519.h>
-#include <openssl/digest.h>
-#include <openssl/hkdf.h>
-#include <openssl/hmac.h>
-#include <openssl/mem.h>
-#include <openssl/sha.h>
-
-namespace cppcose {
-
-using bytevec = std::vector<uint8_t>;
-
-constexpr int kCoseSign1EntryCount = 4;
-constexpr int kCoseSign1ProtectedParams = 0;
-constexpr int kCoseSign1UnprotectedParams = 1;
-constexpr int kCoseSign1Payload = 2;
-constexpr int kCoseSign1Signature = 3;
-
-constexpr int kCoseMac0EntryCount = 4;
-constexpr int kCoseMac0ProtectedParams = 0;
-constexpr int kCoseMac0UnprotectedParams = 1;
-constexpr int kCoseMac0Payload = 2;
-constexpr int kCoseMac0Tag = 3;
-
-constexpr int kCoseEncryptEntryCount = 4;
-constexpr int kCoseEncryptProtectedParams = 0;
-constexpr int kCoseEncryptUnprotectedParams = 1;
-constexpr int kCoseEncryptPayload = 2;
-constexpr int kCoseEncryptRecipients = 3;
-
-enum Label : int {
-    ALGORITHM = 1,
-    KEY_ID = 4,
-    IV = 5,
-    COSE_KEY = -1,
-};
-
-enum CoseKeyAlgorithm : int {
-    AES_GCM_256 = 3,
-    HMAC_256 = 5,
-    ES256 = -7,  // ECDSA with SHA-256
-    EDDSA = -8,
-    ECDH_ES_HKDF_256 = -25,
-};
-
-enum CoseKeyCurve : int { P256 = 1, X25519 = 4, ED25519 = 6 };
-enum CoseKeyType : int { OCTET_KEY_PAIR = 1, EC2 = 2, SYMMETRIC_KEY = 4 };
-enum CoseKeyOps : int { SIGN = 1, VERIFY = 2, ENCRYPT = 3, DECRYPT = 4 };
-
-constexpr int kAesGcmNonceLength = 12;
-constexpr int kAesGcmTagSize = 16;
-constexpr int kAesGcmKeySize = 32;
-
-template <typename T>
-class ErrMsgOr {
-  public:
-    ErrMsgOr(std::string errMsg) : errMsg_(std::move(errMsg)) {}
-    ErrMsgOr(const char* errMsg) : errMsg_(errMsg) {}
-    ErrMsgOr(T val) : value_(std::move(val)) {}
-
-    operator bool() const { return value_.has_value(); }
-
-    T* operator->() & {
-        assert(value_);
-        return &value_.value();
-    }
-    T& operator*() & {
-        assert(value_);
-        return value_.value();
-    };
-    T&& operator*() && {
-        assert(value_);
-        return std::move(value_).value();
-    };
-
-    const std::string& message() { return errMsg_; }
-    std::string moveMessage() { return std::move(errMsg_); }
-
-    T moveValue() {
-        assert(value_);
-        return std::move(value_).value();
-    }
-
-  private:
-    std::string errMsg_;
-    std::optional<T> value_;
-};
-
-class CoseKey {
-  public:
-    CoseKey() {}
-    CoseKey(const CoseKey&) = delete;
-    CoseKey(CoseKey&&) = default;
-
-    enum Label : int {
-        KEY_TYPE = 1,
-        KEY_ID = 2,
-        ALGORITHM = 3,
-        KEY_OPS = 4,
-        CURVE = -1,
-        PUBKEY_X = -2,
-        PUBKEY_Y = -3,
-        PRIVATE_KEY = -4,
-        TEST_KEY = -70000  // Application-defined
-    };
-
-    static ErrMsgOr<CoseKey> parse(const bytevec& coseKey) {
-        auto [parsedKey, _, errMsg] = cppbor::parse(coseKey);
-        if (!parsedKey) return errMsg + " when parsing key";
-        if (!parsedKey->asMap()) return "CoseKey must be a map";
-        return CoseKey(static_cast<cppbor::Map*>(parsedKey.release()));
-    }
-
-    static ErrMsgOr<CoseKey> parse(const bytevec& coseKey, CoseKeyType expectedKeyType,
-                                   CoseKeyAlgorithm expectedAlgorithm, CoseKeyCurve expectedCurve) {
-        auto key = parse(coseKey);
-        if (!key) return key;
-
-        if (!key->checkIntValue(CoseKey::KEY_TYPE, expectedKeyType) ||
-            !key->checkIntValue(CoseKey::ALGORITHM, expectedAlgorithm) ||
-            !key->checkIntValue(CoseKey::CURVE, expectedCurve)) {
-            return "Unexpected key type:";
-        }
-
-        return key;
-    }
-
-    static ErrMsgOr<CoseKey> parseEd25519(const bytevec& coseKey) {
-        auto key = parse(coseKey, OCTET_KEY_PAIR, EDDSA, ED25519);
-        if (!key) return key;
-
-        auto& pubkey = key->getMap().get(PUBKEY_X);
-        if (!pubkey || !pubkey->asBstr() ||
-            pubkey->asBstr()->value().size() != ED25519_PUBLIC_KEY_LEN) {
-            return "Invalid Ed25519 public key";
-        }
-
-        return key;
-    }
-
-    static ErrMsgOr<CoseKey> parseX25519(const bytevec& coseKey, bool requireKid) {
-        auto key = parse(coseKey, OCTET_KEY_PAIR, ECDH_ES_HKDF_256, X25519);
-        if (!key) return key;
-
-        auto& pubkey = key->getMap().get(PUBKEY_X);
-        if (!pubkey || !pubkey->asBstr() ||
-            pubkey->asBstr()->value().size() != X25519_PUBLIC_VALUE_LEN) {
-            return "Invalid X25519 public key";
-        }
-
-        auto& kid = key->getMap().get(KEY_ID);
-        if (requireKid && (!kid || !kid->asBstr())) {
-            return "Missing KID";
-        }
-
-        return key;
-    }
-
-    static ErrMsgOr<CoseKey> parseP256(const bytevec& coseKey) {
-        auto key = parse(coseKey, EC2, ES256, P256);
-        if (!key) return key;
-
-        auto& pubkey_x = key->getMap().get(PUBKEY_X);
-        auto& pubkey_y = key->getMap().get(PUBKEY_Y);
-        if (!pubkey_x || !pubkey_y || !pubkey_x->asBstr() || !pubkey_y->asBstr() ||
-            pubkey_x->asBstr()->value().size() != 32 || pubkey_y->asBstr()->value().size() != 32) {
-            return "Invalid P256 public key";
-        }
-
-        return key;
-    }
-
-    std::optional<int> getIntValue(Label label) {
-        const auto& value = key_->get(label);
-        if (!value || !value->asInt()) return {};
-        return value->asInt()->value();
-    }
-
-    std::optional<bytevec> getBstrValue(Label label) {
-        const auto& value = key_->get(label);
-        if (!value || !value->asBstr()) return {};
-        return value->asBstr()->value();
-    }
-
-    const cppbor::Map& getMap() const { return *key_; }
-    cppbor::Map&& moveMap() { return std::move(*key_); }
-
-    bool checkIntValue(Label label, int expectedValue) {
-        const auto& value = key_->get(label);
-        return value && value->asInt() && value->asInt()->value() == expectedValue;
-    }
-
-    void add(Label label, int value) { key_->add(label, value); }
-    void add(Label label, bytevec value) { key_->add(label, std::move(value)); }
-
-    bytevec encode() { return key_->canonicalize().encode(); }
-
-  private:
-    CoseKey(cppbor::Map* parsedKey) : key_(parsedKey) {}
-
-    // This is the full parsed key structure.
-    std::unique_ptr<cppbor::Map> key_;
-};
-
-ErrMsgOr<bytevec> generateCoseMac0Mac(const bytevec& macKey, const bytevec& externalAad,
-                                      const bytevec& payload);
-ErrMsgOr<cppbor::Array> constructCoseMac0(const bytevec& macKey, const bytevec& externalAad,
-                                          const bytevec& payload);
-ErrMsgOr<bytevec /* payload */> parseCoseMac0(const cppbor::Item* macItem);
-ErrMsgOr<bytevec /* payload */> verifyAndParseCoseMac0(const cppbor::Item* macItem,
-                                                       const bytevec& macKey);
-
-ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
-                                           const bytevec& payload, const bytevec& aad);
-ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, const bytevec& payload,
-                                           const bytevec& aad);
-ErrMsgOr<cppbor::Array> constructCoseSign1(const bytevec& key, cppbor::Map extraProtectedFields,
-                                           const bytevec& payload, const bytevec& aad);
-/**
- * Verify and parse a COSE_Sign1 message, returning the payload.
- *
- * @param ignoreSignature indicates whether signature verification should be skipped.  If true, no
- *        verification of the signature will be done.
- *
- * @param coseSign1 is the COSE_Sign1 to verify and parse.
- *
- * @param signingCoseKey is a CBOR-encoded COSE_Key to use to verify the signature.  The bytevec may
- *        be empty, in which case the function assumes that coseSign1's payload is the COSE_Key to
- *        use, i.e. that coseSign1 is a self-signed "certificate".
- */
-ErrMsgOr<bytevec /* payload */> verifyAndParseCoseSign1(bool ignoreSignature,
-                                                        const cppbor::Array* coseSign1,
-                                                        const bytevec& signingCoseKey,
-                                                        const bytevec& aad);
-
-ErrMsgOr<bytevec> createCoseEncryptCiphertext(const bytevec& key, const bytevec& nonce,
-                                              const bytevec& protectedParams, const bytevec& aad);
-ErrMsgOr<cppbor::Array> constructCoseEncrypt(const bytevec& key, const bytevec& nonce,
-                                             const bytevec& plaintextPayload, const bytevec& aad,
-                                             cppbor::Array recipients);
-ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>> getSenderPubKeyFromCoseEncrypt(
-        const cppbor::Item* encryptItem);
-inline ErrMsgOr<std::pair<bytevec /* pubkey */, bytevec /* key ID */>>
-getSenderPubKeyFromCoseEncrypt(const std::unique_ptr<cppbor::Item>& encryptItem) {
-    return getSenderPubKeyFromCoseEncrypt(encryptItem.get());
-}
-
-ErrMsgOr<bytevec /* plaintextPayload */> decryptCoseEncrypt(const bytevec& key,
-                                                            const cppbor::Item* encryptItem,
-                                                            const bytevec& aad);
-
-ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& senderPubKey, const bytevec& senderPrivKey,
-                                        const bytevec& recipientPubKey, bool senderIsA);
-
-ErrMsgOr<bytevec /* ciphertextWithTag */> aesGcmEncrypt(const bytevec& key, const bytevec& nonce,
-                                                        const bytevec& aad,
-                                                        const bytevec& plaintext);
-ErrMsgOr<bytevec /* plaintext */> aesGcmDecrypt(const bytevec& key, const bytevec& nonce,
-                                                const bytevec& aad,
-                                                const bytevec& ciphertextWithTag);
-
-}  // namespace cppcose
diff --git a/security/keymint/support/include/keymint_support/openssl_utils.h b/security/keymint/support/include/keymint_support/openssl_utils.h
index a0212aa..dee28ba 100644
--- a/security/keymint/support/include/keymint_support/openssl_utils.h
+++ b/security/keymint/support/include/keymint_support/openssl_utils.h
@@ -37,6 +37,7 @@
 MAKE_OPENSSL_PTR_TYPE(BN_CTX)
 MAKE_OPENSSL_PTR_TYPE(EC_GROUP)
 MAKE_OPENSSL_PTR_TYPE(EC_KEY)
+MAKE_OPENSSL_PTR_TYPE(EC_POINT)
 MAKE_OPENSSL_PTR_TYPE(EVP_PKEY)
 MAKE_OPENSSL_PTR_TYPE(EVP_PKEY_CTX)
 MAKE_OPENSSL_PTR_TYPE(RSA)
diff --git a/security/keymint/support/include/remote_prov/remote_prov_utils.h b/security/keymint/support/include/remote_prov/remote_prov_utils.h
index 5e205a2..e4261f3 100644
--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -18,7 +18,7 @@
 
 #include <vector>
 
-#include <cppcose/cppcose.h>
+#include <keymaster/cppcose/cppcose.h>
 
 namespace aidl::android::hardware::security::keymint::remote_prov {
 
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index 3e4f3f7..da10eb2 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -54,6 +54,8 @@
                                             {} /* AAD */);
         if (!coseSign1) return coseSign1.moveMessage();
         eekChain.add(coseSign1.moveValue());
+
+        prev_priv_key = priv_key;
     }
 
     bytevec pub_key(X25519_PUBLIC_VALUE_LEN);
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/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp b/security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp
index 9ca1ee8..31f4854 100644
--- a/security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp
+++ b/security/secureclock/aidl/vts/functional/SecureClockAidlTest.cpp
@@ -185,9 +185,11 @@
 INSTANTIATE_TEST_SUITE_P(PerInstance, SecureClockAidlTest,
                          testing::ValuesIn(SecureClockAidlTest::build_params()),
                          ::android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SecureClockAidlTest);
+
 }  // namespace aidl::android::hardware::security::secureclock::test
 
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
     return RUN_ALL_TESTS();
-}
\ No newline at end of file
+}
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/2.1/default/SensorsV2_1.cpp b/sensors/2.1/default/SensorsV2_1.cpp
index 4c5386a..06446a2 100644
--- a/sensors/2.1/default/SensorsV2_1.cpp
+++ b/sensors/2.1/default/SensorsV2_1.cpp
@@ -46,7 +46,8 @@
         mSensorInfo.fifoMaxEventCount = 0;
         mSensorInfo.requiredPermission = "";
         mSensorInfo.flags = static_cast<uint32_t>(V1_0::SensorFlagBits::ON_CHANGE_MODE |
-                                                  V1_0::SensorFlagBits::WAKE_UP);
+                                                  V1_0::SensorFlagBits::WAKE_UP |
+                                                  V1_0::SensorFlagBits::DATA_INJECTION);
     }
 };
 
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
diff --git a/tv/cec/1.1/vts/functional/VtsHalTvCecV1_1TargetTest.cpp b/tv/cec/1.1/vts/functional/VtsHalTvCecV1_1TargetTest.cpp
index 1eb4643..c5b4b2f 100644
--- a/tv/cec/1.1/vts/functional/VtsHalTvCecV1_1TargetTest.cpp
+++ b/tv/cec/1.1/vts/functional/VtsHalTvCecV1_1TargetTest.cpp
@@ -46,6 +46,7 @@
 
 #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> {
@@ -126,6 +127,19 @@
     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_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;
@@ -196,4 +210,14 @@
             ASSERT_TRUE(ret.isOk());
         }
     }
-}
\ No newline at end of file
+}
+
+TEST_P(HdmiCecTest, IsConnected) {
+    hidl_vec<HdmiPortInfo> ports;
+    Return<void> ret =
+            hdmiCec->getPortInfo([&ports](hidl_vec<HdmiPortInfo> list) { ports = list; });
+    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/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index 9a6ecf7..c4f610e 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -139,6 +139,8 @@
 
     // IP filter can be an MMTP filter's data source.
     caps.linkCaps = {0x00, 0x00, 0x02, 0x00, 0x00};
+    // Support time filter testing
+    caps.bTimeFilter = true;
     _hidl_cb(Result::SUCCESS, caps);
     return Void();
 }
diff --git a/tv/tuner/1.0/vts/functional/Android.bp b/tv/tuner/1.0/vts/functional/Android.bp
index c27a935..6187c73 100644
--- a/tv/tuner/1.0/vts/functional/Android.bp
+++ b/tv/tuner/1.0/vts/functional/Android.bp
@@ -35,6 +35,15 @@
         "DescramblerTests.cpp",
         "LnbTests.cpp",
     ],
+    generated_headers: [
+        "tuner_testing_dynamic_configuration_V1_0_enums",
+        "tuner_testing_dynamic_configuration_V1_0_parser",
+    ],
+    generated_sources: [
+        "tuner_testing_dynamic_configuration_V1_0_enums",
+        "tuner_testing_dynamic_configuration_V1_0_parser",
+    ],
+    header_libs: ["libxsdc-utils"],
     static_libs: [
         "android.hardware.cas@1.0",
         "android.hardware.cas@1.1",
@@ -49,9 +58,12 @@
     ],
     shared_libs: [
         "libbinder",
+        "libxml2",
     ],
     data: [
         ":tuner_frontend_input_ts",
+        ":tuner_frontend_input_es",
+        ":tuner_testing_dynamic_configuration_V1_0",
     ],
     test_suites: [
         "general-tests",
diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.h b/tv/tuner/1.0/vts/functional/FrontendTests.h
index 4974ff3..33ff603 100644
--- a/tv/tuner/1.0/vts/functional/FrontendTests.h
+++ b/tv/tuner/1.0/vts/functional/FrontendTests.h
@@ -132,6 +132,7 @@
     static AssertionResult failure() { return ::testing::AssertionFailure(); }
     static AssertionResult success() { return ::testing::AssertionSuccess(); }
 
+    // TODO: replace with customized dvr input
     void getDefaultSoftwareFrontendPlaybackConfig(DvrConfig& dvrConfig) {
         PlaybackSettings playbackSettings{
                 .statusMask = 0xf,
diff --git a/tv/tuner/1.0/vts/functional/LnbTests.cpp b/tv/tuner/1.0/vts/functional/LnbTests.cpp
index 9080f59..9338c73 100644
--- a/tv/tuner/1.0/vts/functional/LnbTests.cpp
+++ b/tv/tuner/1.0/vts/functional/LnbTests.cpp
@@ -48,10 +48,11 @@
     return AssertionResult(status == Result::SUCCESS);
 }
 
-AssertionResult LnbTests::openLnbByName(string lnbName) {
+AssertionResult LnbTests::openLnbByName(string lnbName, uint32_t& id) {
     Result status;
-    mService->openLnbByName(lnbName, [&](Result result, uint32_t /*lnbId*/, const sp<ILnb>& lnb) {
+    mService->openLnbByName(lnbName, [&](Result result, uint32_t lnbId, const sp<ILnb>& lnb) {
         mLnb = lnb;
+        id = lnbId;
         status = result;
     });
 
diff --git a/tv/tuner/1.0/vts/functional/LnbTests.h b/tv/tuner/1.0/vts/functional/LnbTests.h
index 2fdbe2c..62b42ff 100644
--- a/tv/tuner/1.0/vts/functional/LnbTests.h
+++ b/tv/tuner/1.0/vts/functional/LnbTests.h
@@ -64,7 +64,7 @@
 
     AssertionResult getLnbIds(vector<uint32_t>& ids);
     AssertionResult openLnbById(uint32_t lnbId);
-    AssertionResult openLnbByName(string lnbName);
+    AssertionResult openLnbByName(string lnbName, uint32_t& lnbId);
     AssertionResult setLnbCallback();
     AssertionResult setVoltage(LnbVoltage voltage);
     AssertionResult setTone(LnbTone tone);
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index 891619a..4c92665 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -18,16 +18,15 @@
 
 namespace {
 
-AssertionResult TunerBroadcastHidlTest::filterDataOutputTest(vector<string> /*goldenOutputFiles*/) {
+AssertionResult TunerBroadcastHidlTest::filterDataOutputTest() {
     return filterDataOutputTestBase(mFilterTests);
 }
 
-AssertionResult TunerPlaybackHidlTest::filterDataOutputTest(vector<string> /*goldenOutputFiles*/) {
+AssertionResult TunerPlaybackHidlTest::filterDataOutputTest() {
     return filterDataOutputTestBase(mFilterTests);
 }
 
-AssertionResult TunerDescramblerHidlTest::filterDataOutputTest(
-        vector<string> /*goldenOutputFiles*/) {
+AssertionResult TunerDescramblerHidlTest::filterDataOutputTest() {
     return filterDataOutputTestBase(mFilterTests);
 }
 
@@ -57,13 +56,16 @@
 }
 
 void TunerFilterHidlTest::testTimeFilter(TimeFilterConfig filterConf) {
-    if (!filterConf.supportTimeFilter) {
+    if (!timeFilter.support) {
         return;
     }
     uint32_t demuxId;
     sp<IDemux> demux;
+    DemuxCapabilities caps;
 
     ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    ASSERT_TRUE(mDemuxTests.getDemuxCaps(caps));
+    ASSERT_TRUE(caps.bTimeFilter);
     mFilterTests.setDemux(demux);
     ASSERT_TRUE(mFilterTests.openTimeFilterInDemux());
     ASSERT_TRUE(mFilterTests.setTimeStamp(filterConf.timeStamp));
@@ -75,26 +77,20 @@
 
 void TunerBroadcastHidlTest::broadcastSingleFilterTest(FilterConfig filterConf,
                                                        FrontendConfig frontendConf) {
-    if (!frontendConf.enable) {
-        return;
-    }
     uint32_t feId;
     uint32_t demuxId;
     sp<IDemux> demux;
     uint32_t filterId;
 
     mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
-    if (feId == INVALID_ID) {
-        // TODO broadcast test on Cuttlefish needs licensed ts input,
-        // these tests are runnable on vendor device with real frontend module
-        // or with manual ts installing and use DVBT frontend.
-        return;
-    }
     ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
     ASSERT_TRUE(mFrontendTests.setFrontendCallback());
     if (mLnbId) {
         ASSERT_TRUE(mFrontendTests.setLnb(*mLnbId));
     }
+    if (frontendConf.isSoftwareFe) {
+        mFrontendTests.setSoftwareFrontendDvrConfig(dvrMap[live.dvrSoftwareFeId]);
+    }
     ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
     ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
     mFrontendTests.setDemux(demux);
@@ -106,7 +102,7 @@
     ASSERT_TRUE(mFilterTests.startFilter(filterId));
     // tune test
     ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
-    ASSERT_TRUE(filterDataOutputTest(goldenOutputFiles));
+    ASSERT_TRUE(filterDataOutputTest());
     ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
     ASSERT_TRUE(mFilterTests.stopFilter(filterId));
     ASSERT_TRUE(mFilterTests.closeFilter(filterId));
@@ -117,14 +113,16 @@
 void TunerBroadcastHidlTest::broadcastSingleFilterTestWithLnb(FilterConfig filterConf,
                                                               FrontendConfig frontendConf,
                                                               LnbConfig lnbConf) {
-    vector<uint32_t> ids;
-    ASSERT_TRUE(mLnbTests.getLnbIds(ids));
-    if (!lnbConf.usingLnb) {
-        return;
+    if (lnbConf.name.compare(emptyHardwareId) == 0) {
+        vector<uint32_t> ids;
+        ASSERT_TRUE(mLnbTests.getLnbIds(ids));
+        ASSERT_TRUE(ids.size() > 0);
+        ASSERT_TRUE(mLnbTests.openLnbById(ids[0]));
+        mLnbId = &ids[0];
+    } else {
+        mLnbId = (uint32_t*)malloc(sizeof(uint32_t));
+        ASSERT_TRUE(mLnbTests.openLnbByName(lnbConf.name, *mLnbId));
     }
-    ASSERT_TRUE(ids.size() > 0);
-    ASSERT_TRUE(mLnbTests.openLnbById(ids[0]));
-    *mLnbId = ids[0];
     ASSERT_TRUE(mLnbTests.setLnbCallback());
     ASSERT_TRUE(mLnbTests.setVoltage(lnbConf.voltage));
     ASSERT_TRUE(mLnbTests.setTone(lnbConf.tone));
@@ -152,7 +150,7 @@
     mDvrTests.startPlaybackInputThread(dvrConf.playbackInputFile, dvrConf.settings.playback());
     ASSERT_TRUE(mDvrTests.startDvrPlayback());
     ASSERT_TRUE(mFilterTests.startFilter(filterId));
-    ASSERT_TRUE(filterDataOutputTest(goldenOutputFiles));
+    ASSERT_TRUE(filterDataOutputTest());
     mDvrTests.stopPlaybackThread();
     ASSERT_TRUE(mFilterTests.stopFilter(filterId));
     ASSERT_TRUE(mDvrTests.stopDvrPlayback());
@@ -163,9 +161,6 @@
 
 void TunerRecordHidlTest::recordSingleFilterTest(FilterConfig filterConf,
                                                  FrontendConfig frontendConf, DvrConfig dvrConf) {
-    if (!frontendConf.enable) {
-        return;
-    }
     uint32_t feId;
     uint32_t demuxId;
     sp<IDemux> demux;
@@ -179,6 +174,9 @@
     if (mLnbId) {
         ASSERT_TRUE(mFrontendTests.setLnb(*mLnbId));
     }
+    if (frontendConf.isSoftwareFe) {
+        mFrontendTests.setSoftwareFrontendDvrConfig(dvrMap[record.dvrSoftwareFeId]);
+    }
     ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
     ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
     mFilterTests.setDemux(demux);
@@ -213,18 +211,23 @@
 void TunerRecordHidlTest::recordSingleFilterTestWithLnb(FilterConfig filterConf,
                                                         FrontendConfig frontendConf,
                                                         DvrConfig dvrConf, LnbConfig lnbConf) {
-    vector<uint32_t> ids;
-    ASSERT_TRUE(mLnbTests.getLnbIds(ids));
-    if (!lnbConf.usingLnb) {
-        return;
+    if (lnbConf.name.compare(emptyHardwareId) == 0) {
+        vector<uint32_t> ids;
+        ASSERT_TRUE(mLnbTests.getLnbIds(ids));
+        ASSERT_TRUE(ids.size() > 0);
+        ASSERT_TRUE(mLnbTests.openLnbById(ids[0]));
+        mLnbId = &ids[0];
+    } else {
+        mLnbId = (uint32_t*)malloc(sizeof(uint32_t));
+        ASSERT_TRUE(mLnbTests.openLnbByName(lnbConf.name, *mLnbId));
     }
-    ASSERT_TRUE(ids.size() > 0);
-    ASSERT_TRUE(mLnbTests.openLnbById(ids[0]));
-    *mLnbId = ids[0];
     ASSERT_TRUE(mLnbTests.setLnbCallback());
     ASSERT_TRUE(mLnbTests.setVoltage(lnbConf.voltage));
     ASSERT_TRUE(mLnbTests.setTone(lnbConf.tone));
     ASSERT_TRUE(mLnbTests.setSatellitePosition(lnbConf.position));
+    for (auto msgName : lnbRecord.diseqcMsgs) {
+        ASSERT_TRUE(mLnbTests.sendDiseqcMessage(diseqcMsgMap[msgName]));
+    }
     recordSingleFilterTest(filterConf, frontendConf, dvrConf);
     ASSERT_TRUE(mLnbTests.closeLnb());
     mLnbId = nullptr;
@@ -271,9 +274,6 @@
 void TunerDescramblerHidlTest::scrambledBroadcastTest(set<struct FilterConfig> mediaFilterConfs,
                                                       FrontendConfig frontendConf,
                                                       DescramblerConfig descConfig) {
-    if (!frontendConf.enable) {
-        return;
-    }
     uint32_t feId;
     uint32_t demuxId;
     sp<IDemux> demux;
@@ -283,14 +283,11 @@
     set<uint32_t>::iterator id;
 
     mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
-    if (feId == INVALID_ID) {
-        // TODO broadcast test on Cuttlefish needs licensed ts input,
-        // these tests are runnable on vendor device with real frontend module
-        // or with manual ts installing and use DVBT frontend.
-        return;
-    }
     ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
     ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+    if (frontendConf.isSoftwareFe) {
+        mFrontendTests.setSoftwareFrontendDvrConfig(dvrMap[descrambling.dvrSoftwareFeId]);
+    }
     ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
     ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
     mFilterTests.setDemux(demux);
@@ -305,7 +302,7 @@
     TunerKeyToken token;
     ASSERT_TRUE(mDescramblerTests.getKeyToken(descConfig.casSystemId, descConfig.provisionStr,
                                               descConfig.hidlPvtData, token));
-    ASSERT_TRUE(mDescramblerTests.setKeyToken(token));
+    mDescramblerTests.setKeyToken(token);
     vector<DemuxPid> pids;
     DemuxPid pid;
     for (config = mediaFilterConfs.begin(); config != mediaFilterConfs.end(); config++) {
@@ -319,7 +316,7 @@
     }
     // tune test
     ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
-    ASSERT_TRUE(filterDataOutputTest(goldenOutputFiles));
+    ASSERT_TRUE(filterDataOutputTest());
     ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
     for (id = filterIds.begin(); id != filterIds.end(); id++) {
         ASSERT_TRUE(mFilterTests.stopFilter(*id));
@@ -337,44 +334,37 @@
 
 TEST_P(TunerFrontendHidlTest, TuneFrontend) {
     description("Tune one Frontend with specific setting and check Lock event");
-    mFrontendTests.tuneTest(frontendArray[defaultFrontend]);
+    mFrontendTests.tuneTest(frontendMap[live.frontendId]);
 }
 
 TEST_P(TunerFrontendHidlTest, AutoScanFrontend) {
     description("Run an auto frontend scan with specific setting and check lock scanMessage");
-    mFrontendTests.scanTest(frontendScanArray[defaultScanFrontend], FrontendScanType::SCAN_AUTO);
+    mFrontendTests.scanTest(frontendMap[scan.frontendId], FrontendScanType::SCAN_AUTO);
 }
 
 TEST_P(TunerFrontendHidlTest, BlindScanFrontend) {
     description("Run an blind frontend scan with specific setting and check lock scanMessage");
-    mFrontendTests.scanTest(frontendScanArray[defaultScanFrontend], FrontendScanType::SCAN_BLIND);
-}
-
-TEST_P(TunerLnbHidlTest, OpenLnbByName) {
-    description("Open and configure an Lnb with name then send a diseqc msg to it.");
-    ASSERT_TRUE(mLnbTests.openLnbByName(lnbArray[LNB_EXTERNAL].name));
-    ASSERT_TRUE(mLnbTests.setLnbCallback());
-    ASSERT_TRUE(mLnbTests.setVoltage(lnbArray[LNB_EXTERNAL].voltage));
-    ASSERT_TRUE(mLnbTests.setTone(lnbArray[LNB_EXTERNAL].tone));
-    ASSERT_TRUE(mLnbTests.setSatellitePosition(lnbArray[LNB_EXTERNAL].position));
-    ASSERT_TRUE(mLnbTests.sendDiseqcMessage(diseqcMsgArray[DISEQC_POWER_ON]));
-    ASSERT_TRUE(mLnbTests.closeLnb());
+    mFrontendTests.scanTest(frontendMap[scan.frontendId], FrontendScanType::SCAN_BLIND);
 }
 
 TEST_P(TunerLnbHidlTest, SendDiseqcMessageToLnb) {
     description("Open and configure an Lnb with specific settings then send a diseqc msg to it.");
-    vector<uint32_t> ids;
-    ASSERT_TRUE(mLnbTests.getLnbIds(ids));
-    if (!lnbArray[LNB0].usingLnb) {
-        return;
+    if (lnbMap[lnbLive.lnbId].name.compare(emptyHardwareId) == 0) {
+        vector<uint32_t> ids;
+        ASSERT_TRUE(mLnbTests.getLnbIds(ids));
+        ASSERT_TRUE(ids.size() > 0);
+        ASSERT_TRUE(mLnbTests.openLnbById(ids[0]));
+    } else {
+        uint32_t id;
+        ASSERT_TRUE(mLnbTests.openLnbByName(lnbMap[lnbLive.lnbId].name, id));
     }
-    ASSERT_TRUE(ids.size() > 0);
-    ASSERT_TRUE(mLnbTests.openLnbById(ids[0]));
     ASSERT_TRUE(mLnbTests.setLnbCallback());
-    ASSERT_TRUE(mLnbTests.setVoltage(lnbArray[LNB0].voltage));
-    ASSERT_TRUE(mLnbTests.setTone(lnbArray[LNB0].tone));
-    ASSERT_TRUE(mLnbTests.setSatellitePosition(lnbArray[LNB0].position));
-    ASSERT_TRUE(mLnbTests.sendDiseqcMessage(diseqcMsgArray[DISEQC_POWER_ON]));
+    ASSERT_TRUE(mLnbTests.setVoltage(lnbMap[lnbLive.lnbId].voltage));
+    ASSERT_TRUE(mLnbTests.setTone(lnbMap[lnbLive.lnbId].tone));
+    ASSERT_TRUE(mLnbTests.setSatellitePosition(lnbMap[lnbLive.lnbId].position));
+    for (auto msgName : lnbLive.diseqcMsgs) {
+        ASSERT_TRUE(mLnbTests.sendDiseqcMessage(diseqcMsgMap[msgName]));
+    }
     ASSERT_TRUE(mLnbTests.closeLnb());
 }
 
@@ -383,7 +373,7 @@
     uint32_t feId;
     uint32_t demuxId;
     sp<IDemux> demux;
-    mFrontendTests.getFrontendIdByType(frontendArray[defaultFrontend].type, feId);
+    mFrontendTests.getFrontendIdByType(frontendMap[live.frontendId].type, feId);
     ASSERT_TRUE(feId != INVALID_ID);
     ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
     ASSERT_TRUE(mFrontendTests.setFrontendCallback());
@@ -395,6 +385,9 @@
 
 TEST_P(TunerDemuxHidlTest, getAvSyncTime) {
     description("Get the A/V sync time from a PCR filter.");
+    if (live.pcrFilterId.compare(emptyHardwareId) == 0) {
+        return;
+    }
     uint32_t feId;
     uint32_t demuxId;
     sp<IDemux> demux;
@@ -403,22 +396,22 @@
     uint32_t avSyncHwId;
     sp<IFilter> mediaFilter;
 
-    mFrontendTests.getFrontendIdByType(frontendArray[defaultFrontend].type, feId);
+    mFrontendTests.getFrontendIdByType(frontendMap[live.frontendId].type, feId);
     ASSERT_TRUE(feId != INVALID_ID);
     ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
     ASSERT_TRUE(mFrontendTests.setFrontendCallback());
     ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
     ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
     mFilterTests.setDemux(demux);
-    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_VIDEO1].type,
-                                               filterArray[TS_VIDEO1].bufferSize));
+    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterMap[live.videoFilterId].type,
+                                               filterMap[live.videoFilterId].bufferSize));
     ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(mediaFilterId));
-    ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_VIDEO1].settings, mediaFilterId));
+    ASSERT_TRUE(mFilterTests.configFilter(filterMap[live.videoFilterId].settings, mediaFilterId));
     mediaFilter = mFilterTests.getFilterById(mediaFilterId);
-    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_PCR0].type,
-                                               filterArray[TS_PCR0].bufferSize));
+    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterMap[live.pcrFilterId].type,
+                                               filterMap[live.pcrFilterId].bufferSize));
     ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(pcrFilterId));
-    ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_PCR0].settings, pcrFilterId));
+    ASSERT_TRUE(mFilterTests.configFilter(filterMap[live.pcrFilterId].settings, pcrFilterId));
     ASSERT_TRUE(mDemuxTests.getAvSyncId(mediaFilter, avSyncHwId));
     ASSERT_TRUE(pcrFilterId == avSyncHwId);
     ASSERT_TRUE(mDemuxTests.getAvSyncTime(pcrFilterId));
@@ -431,7 +424,7 @@
 TEST_P(TunerFilterHidlTest, StartFilterInDemux) {
     description("Open and start a filter in Demux.");
     // TODO use paramterized tests
-    configSingleFilterInDemuxTest(filterArray[TS_VIDEO0], frontendArray[defaultFrontend]);
+    configSingleFilterInDemuxTest(filterMap[live.videoFilterId], frontendMap[live.frontendId]);
 }
 
 TEST_P(TunerFilterHidlTest, SetFilterLinkage) {
@@ -448,11 +441,9 @@
             if (caps.linkCaps[i] & (bitMask << j)) {
                 uint32_t sourceFilterId;
                 uint32_t sinkFilterId;
-                ASSERT_TRUE(mFilterTests.openFilterInDemux(filterLinkageTypes[SOURCE][i],
-                                                           FMQ_SIZE_16M));
+                ASSERT_TRUE(mFilterTests.openFilterInDemux(getLinkageFilterType(i), FMQ_SIZE_16M));
                 ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(sourceFilterId));
-                ASSERT_TRUE(
-                        mFilterTests.openFilterInDemux(filterLinkageTypes[SINK][j], FMQ_SIZE_16M));
+                ASSERT_TRUE(mFilterTests.openFilterInDemux(getLinkageFilterType(j), FMQ_SIZE_16M));
                 ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(sinkFilterId));
                 ASSERT_TRUE(mFilterTests.setFilterDataSource(sourceFilterId, sinkFilterId));
                 ASSERT_TRUE(mFilterTests.setFilterDataSourceToDemux(sinkFilterId));
@@ -467,120 +458,87 @@
 TEST_P(TunerFilterHidlTest, testTimeFilter) {
     description("Open a timer filter in Demux and set time stamp.");
     // TODO use paramterized tests
-    testTimeFilter(timeFilterArray[TIMER0]);
+    testTimeFilter(timeFilterMap[timeFilter.timeFilterId]);
 }
 
 TEST_P(TunerBroadcastHidlTest, BroadcastDataFlowVideoFilterTest) {
     description("Test Video Filter functionality in Broadcast use case.");
-    broadcastSingleFilterTest(filterArray[TS_VIDEO1], frontendArray[defaultFrontend]);
+    broadcastSingleFilterTest(filterMap[live.videoFilterId], frontendMap[live.frontendId]);
 }
 
 TEST_P(TunerBroadcastHidlTest, BroadcastDataFlowAudioFilterTest) {
     description("Test Audio Filter functionality in Broadcast use case.");
-    broadcastSingleFilterTest(filterArray[TS_AUDIO0], frontendArray[defaultFrontend]);
+    broadcastSingleFilterTest(filterMap[live.audioFilterId], frontendMap[live.frontendId]);
 }
 
 TEST_P(TunerBroadcastHidlTest, BroadcastDataFlowSectionFilterTest) {
     description("Test Section Filter functionality in Broadcast use case.");
-    broadcastSingleFilterTest(filterArray[TS_SECTION0], frontendArray[defaultFrontend]);
+    if (live.sectionFilterId.compare(emptyHardwareId) == 0) {
+        return;
+    }
+    broadcastSingleFilterTest(filterMap[live.sectionFilterId], frontendMap[live.frontendId]);
 }
 
 TEST_P(TunerBroadcastHidlTest, IonBufferTest) {
     description("Test the av filter data bufferring.");
-    broadcastSingleFilterTest(filterArray[TS_VIDEO0], frontendArray[defaultFrontend]);
+    broadcastSingleFilterTest(filterMap[live.videoFilterId], frontendMap[live.frontendId]);
 }
 
 TEST_P(TunerBroadcastHidlTest, LnbBroadcastDataFlowVideoFilterTest) {
     description("Test Video Filter functionality in Broadcast with Lnb use case.");
-    broadcastSingleFilterTest(filterArray[TS_VIDEO0], frontendArray[DVBS]);
-}
-
-TEST_P(TunerBroadcastHidlTest, BroadcastEsDataFlowMediaFiltersTest) {
-    description("Test Meida Filters functionality in Broadcast use case with ES input.");
-    uint32_t feId;
-    uint32_t demuxId;
-    sp<IDemux> demux;
-    uint32_t filterId;
-
-    mFrontendTests.getFrontendIdByType(frontendArray[defaultFrontend].type, feId);
-    if (feId == INVALID_ID) {
-        // TODO broadcast test on Cuttlefish needs licensed ts input,
-        // these tests are runnable on vendor device with real frontend module
-        // or with manual ts installing and use defaultFrontend frontend.
+    if (!lnbLive.support) {
         return;
     }
-    ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
-    ASSERT_TRUE(mFrontendTests.setFrontendCallback());
-    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
-    ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
-    mFrontendTests.setDemux(demux);
-    mFilterTests.setDemux(demux);
-    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_AUDIO1].type,
-                                               filterArray[TS_AUDIO1].bufferSize));
-    ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
-    ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_AUDIO1].settings, filterId));
-    ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId, filterArray[TS_AUDIO1].getMqDesc));
-    ASSERT_TRUE(mFilterTests.startFilter(filterId));
-    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_VIDEO1].type,
-                                               filterArray[TS_VIDEO1].bufferSize));
-    ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
-    ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_VIDEO1].settings, filterId));
-    ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId, filterArray[TS_VIDEO1].getMqDesc));
-    ASSERT_TRUE(mFilterTests.startFilter(filterId));
-    // tune test
-    PlaybackSettings playbackSettings{
-            .statusMask = 0xf,
-            .lowThreshold = 0x1000,
-            .highThreshold = 0x07fff,
-            .dataFormat = DataFormat::ES,
-            .packetSize = 188,
-    };
-    DvrConfig dvrConfig{
-            .type = DvrType::PLAYBACK,
-            .playbackInputFile = "/data/local/tmp/test.es",
-            .bufferSize = FMQ_SIZE_4M,
-    };
-    dvrConfig.settings.playback(playbackSettings);
-    mFrontendTests.setSoftwareFrontendDvrConfig(dvrConfig);
-    ASSERT_TRUE(
-            mFrontendTests.tuneFrontend(frontendArray[defaultFrontend], true /*testWithDemux*/));
-    ASSERT_TRUE(filterDataOutputTest(goldenOutputFiles));
-    ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
-    ASSERT_TRUE(mFilterTests.stopFilter(filterId));
-    ASSERT_TRUE(mFilterTests.closeFilter(filterId));
-    ASSERT_TRUE(mDemuxTests.closeDemux());
-    ASSERT_TRUE(mFrontendTests.closeFrontend());
+    broadcastSingleFilterTestWithLnb(filterMap[lnbLive.videoFilterId],
+                                     frontendMap[lnbLive.frontendId], lnbMap[lnbLive.lnbId]);
 }
 
 TEST_P(TunerPlaybackHidlTest, PlaybackDataFlowWithTsSectionFilterTest) {
     description("Feed ts data from playback and configure Ts section filter to get output");
-    playbackSingleFilterTest(filterArray[TS_SECTION0], dvrArray[DVR_PLAYBACK0]);
+    if (!playback.support || playback.sectionFilterId.compare(emptyHardwareId) == 0) {
+        return;
+    }
+    playbackSingleFilterTest(filterMap[playback.sectionFilterId], dvrMap[playback.dvrId]);
 }
 
 TEST_P(TunerRecordHidlTest, AttachFiltersToRecordTest) {
     description("Attach a single filter to the record dvr test.");
     // TODO use paramterized tests
-    attachSingleFilterToRecordDvrTest(filterArray[TS_RECORD0], frontendArray[defaultFrontend],
-                                      dvrArray[DVR_RECORD0]);
+    if (!record.support) {
+        return;
+    }
+    attachSingleFilterToRecordDvrTest(filterMap[record.recordFilterId],
+                                      frontendMap[record.frontendId], dvrMap[record.dvrRecordId]);
 }
 
 TEST_P(TunerRecordHidlTest, RecordDataFlowWithTsRecordFilterTest) {
     description("Feed ts data from frontend to recording and test with ts record filter");
-    recordSingleFilterTest(filterArray[TS_RECORD0], frontendArray[defaultFrontend],
-                           dvrArray[DVR_RECORD0]);
+    if (!record.support) {
+        return;
+    }
+    recordSingleFilterTest(filterMap[record.recordFilterId], frontendMap[record.frontendId],
+                           dvrMap[record.dvrRecordId]);
 }
 
 TEST_P(TunerRecordHidlTest, LnbRecordDataFlowWithTsRecordFilterTest) {
     description("Feed ts data from Fe with Lnb to recording and test with ts record filter");
-    recordSingleFilterTest(filterArray[TS_RECORD0], frontendArray[DVBS], dvrArray[DVR_RECORD0]);
+    if (lnbRecord.support) {
+        return;
+    }
+    recordSingleFilterTestWithLnb(filterMap[lnbRecord.recordFilterId],
+                                  frontendMap[lnbRecord.frontendId], dvrMap[lnbRecord.dvrRecordId],
+                                  lnbMap[lnbRecord.lnbId]);
 }
 
 TEST_P(TunerDescramblerHidlTest, CreateDescrambler) {
     description("Create Descrambler");
+    if (descrambling.support) {
+        return;
+    }
     uint32_t feId;
     uint32_t demuxId;
     sp<IDemux> demux;
-    mFrontendTests.getFrontendIdByType(frontendArray[defaultFrontend].type, feId);
+    mFrontendTests.getFrontendIdByType(frontendMap[descrambling.frontendId].type, feId);
     ASSERT_TRUE(feId != INVALID_ID);
     ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
     ASSERT_TRUE(mFrontendTests.setFrontendCallback());
@@ -594,10 +552,14 @@
 
 TEST_P(TunerDescramblerHidlTest, ScrambledBroadcastDataFlowMediaFiltersTest) {
     description("Test ts audio filter in scrambled broadcast use case");
+    if (descrambling.support) {
+        return;
+    }
     set<FilterConfig> filterConfs;
-    filterConfs.insert(filterArray[TS_AUDIO0]);
-    filterConfs.insert(filterArray[TS_VIDEO1]);
-    scrambledBroadcastTest(filterConfs, frontendArray[defaultFrontend], descramblerArray[DESC_0]);
+    filterConfs.insert(static_cast<FilterConfig>(filterMap[descrambling.audioFilterId]));
+    filterConfs.insert(static_cast<FilterConfig>(filterMap[descrambling.videoFilterId]));
+    scrambledBroadcastTest(filterConfs, frontendMap[descrambling.frontendId],
+                           descramblerMap[descrambling.descramblerId]);
 }
 
 INSTANTIATE_TEST_SUITE_P(
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h
index 5a23ca5..e240604 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h
@@ -20,6 +20,9 @@
 #include "LnbTests.h"
 
 using android::hardware::tv::tuner::V1_0::DataFormat;
+using android::hardware::tv::tuner::V1_0::DemuxAlpFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxTlvFilterType;
 using android::hardware::tv::tuner::V1_0::IDescrambler;
 
 static AssertionResult success() {
@@ -28,14 +31,22 @@
 
 namespace {
 
-void initConfiguration() {
+bool initConfiguration() {
+    if (!TunerTestingConfigReader::checkConfigFileExists()) {
+        return false;
+    }
     initFrontendConfig();
-    initFrontendScanConfig();
-    initLnbConfig();
     initFilterConfig();
-    initTimeFilterConfig();
     initDvrConfig();
+    initLnbConfig();
+    initTimeFilterConfig();
     initDescramblerConfig();
+    connectHardwaresToTestCases();
+    if (!validateConnections()) {
+        ALOGW("[vts] failed to validate connections.");
+        return false;
+    }
+    return true;
 }
 
 AssertionResult filterDataOutputTestBase(FilterTests tests) {
@@ -53,7 +64,7 @@
     virtual void SetUp() override {
         mService = ITuner::getService(GetParam());
         ASSERT_NE(mService, nullptr);
-        initConfiguration();
+        ASSERT_TRUE(initConfiguration());
 
         mFrontendTests.setService(mService);
     }
@@ -75,7 +86,7 @@
     virtual void SetUp() override {
         mService = ITuner::getService(GetParam());
         ASSERT_NE(mService, nullptr);
-        initConfiguration();
+        ASSERT_TRUE(initConfiguration());
 
         mLnbTests.setService(mService);
     }
@@ -97,7 +108,7 @@
     virtual void SetUp() override {
         mService = ITuner::getService(GetParam());
         ASSERT_NE(mService, nullptr);
-        initConfiguration();
+        ASSERT_TRUE(initConfiguration());
 
         mFrontendTests.setService(mService);
         mDemuxTests.setService(mService);
@@ -123,7 +134,7 @@
     virtual void SetUp() override {
         mService = ITuner::getService(GetParam());
         ASSERT_NE(mService, nullptr);
-        initConfiguration();
+        ASSERT_TRUE(initConfiguration());
 
         mFrontendTests.setService(mService);
         mDemuxTests.setService(mService);
@@ -138,6 +149,29 @@
     void configSingleFilterInDemuxTest(FilterConfig filterConf, FrontendConfig frontendConf);
     void testTimeFilter(TimeFilterConfig filterConf);
 
+    DemuxFilterType getLinkageFilterType(int bit) {
+        DemuxFilterType type;
+        type.mainType = static_cast<DemuxFilterMainType>(1 << bit);
+        switch (type.mainType) {
+            case DemuxFilterMainType::TS:
+                type.subType.tsFilterType(DemuxTsFilterType::UNDEFINED);
+                break;
+            case DemuxFilterMainType::MMTP:
+                type.subType.mmtpFilterType(DemuxMmtpFilterType::UNDEFINED);
+                break;
+            case DemuxFilterMainType::IP:
+                type.subType.ipFilterType(DemuxIpFilterType::UNDEFINED);
+                break;
+            case DemuxFilterMainType::TLV:
+                type.subType.tlvFilterType(DemuxTlvFilterType::UNDEFINED);
+                break;
+            case DemuxFilterMainType::ALP:
+                type.subType.alpFilterType(DemuxAlpFilterType::UNDEFINED);
+                break;
+        }
+        return type;
+    }
+
     sp<ITuner> mService;
     FrontendTests mFrontendTests;
     DemuxTests mDemuxTests;
@@ -152,7 +186,7 @@
     virtual void SetUp() override {
         mService = ITuner::getService(GetParam());
         ASSERT_NE(mService, nullptr);
-        initConfiguration();
+        ASSERT_TRUE(initConfiguration());
 
         mFrontendTests.setService(mService);
         mDemuxTests.setService(mService);
@@ -173,7 +207,7 @@
     LnbTests mLnbTests;
     DvrTests mDvrTests;
 
-    AssertionResult filterDataOutputTest(vector<string> goldenOutputFiles);
+    AssertionResult filterDataOutputTest();
 
     void broadcastSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf);
     void broadcastSingleFilterTestWithLnb(FilterConfig filterConf, FrontendConfig frontendConf,
@@ -191,7 +225,7 @@
     virtual void SetUp() override {
         mService = ITuner::getService(GetParam());
         ASSERT_NE(mService, nullptr);
-        initConfiguration();
+        ASSERT_TRUE(initConfiguration());
 
         mFrontendTests.setService(mService);
         mDemuxTests.setService(mService);
@@ -210,7 +244,7 @@
     FilterTests mFilterTests;
     DvrTests mDvrTests;
 
-    AssertionResult filterDataOutputTest(vector<string> goldenOutputFiles);
+    AssertionResult filterDataOutputTest();
 
     void playbackSingleFilterTest(FilterConfig filterConf, DvrConfig dvrConf);
 };
@@ -223,7 +257,7 @@
     virtual void SetUp() override {
         mService = ITuner::getService(GetParam());
         ASSERT_NE(mService, nullptr);
-        initConfiguration();
+        ASSERT_TRUE(initConfiguration());
 
         mFrontendTests.setService(mService);
         mDemuxTests.setService(mService);
@@ -265,7 +299,7 @@
         mCasService = IMediaCasService::getService();
         ASSERT_NE(mService, nullptr);
         ASSERT_NE(mCasService, nullptr);
-        initConfiguration();
+        ASSERT_TRUE(initConfiguration());
 
         mFrontendTests.setService(mService);
         mDemuxTests.setService(mService);
@@ -281,7 +315,7 @@
 
     void scrambledBroadcastTest(set<struct FilterConfig> mediaFilterConfs,
                                 FrontendConfig frontendConf, DescramblerConfig descConfig);
-    AssertionResult filterDataOutputTest(vector<string> /*goldenOutputFiles*/);
+    AssertionResult filterDataOutputTest();
 
     sp<ITuner> mService;
     sp<IMediaCasService> mCasService;
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
index 834e296..65f8615 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
@@ -21,366 +21,224 @@
 #include <hidl/Status.h>
 #include <hidlmemory/FrameworkUtils.h>
 
-using android::hardware::tv::tuner::V1_0::DataFormat;
-using android::hardware::tv::tuner::V1_0::DemuxAlpFilterType;
-using android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
+#include "../../../config/TunerTestingConfigReader.h"
+
 using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
-using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
-using android::hardware::tv::tuner::V1_0::DemuxFilterType;
-using android::hardware::tv::tuner::V1_0::DemuxIpFilterType;
-using android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
-using android::hardware::tv::tuner::V1_0::DemuxRecordScIndexType;
-using android::hardware::tv::tuner::V1_0::DemuxTlvFilterType;
-using android::hardware::tv::tuner::V1_0::DemuxTpid;
 using android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
-using android::hardware::tv::tuner::V1_0::DvrSettings;
-using android::hardware::tv::tuner::V1_0::DvrType;
 using android::hardware::tv::tuner::V1_0::FrontendDvbtBandwidth;
-using android::hardware::tv::tuner::V1_0::FrontendDvbtCoderate;
-using android::hardware::tv::tuner::V1_0::FrontendDvbtConstellation;
-using android::hardware::tv::tuner::V1_0::FrontendDvbtGuardInterval;
-using android::hardware::tv::tuner::V1_0::FrontendDvbtHierarchy;
 using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings;
-using android::hardware::tv::tuner::V1_0::FrontendDvbtStandard;
 using android::hardware::tv::tuner::V1_0::FrontendDvbtTransmissionMode;
 using android::hardware::tv::tuner::V1_0::FrontendSettings;
 using android::hardware::tv::tuner::V1_0::FrontendStatus;
 using android::hardware::tv::tuner::V1_0::FrontendStatusType;
 using android::hardware::tv::tuner::V1_0::FrontendType;
-using android::hardware::tv::tuner::V1_0::LnbPosition;
-using android::hardware::tv::tuner::V1_0::LnbTone;
-using android::hardware::tv::tuner::V1_0::LnbVoltage;
-using android::hardware::tv::tuner::V1_0::PlaybackSettings;
-using android::hardware::tv::tuner::V1_0::RecordSettings;
 
 using namespace std;
+using namespace android::media::tuner::testing::configuration::V1_0;
 
-const uint32_t FMQ_SIZE_512K = 0x80000;
-const uint32_t FMQ_SIZE_1M = 0x100000;
 const uint32_t FMQ_SIZE_4M = 0x400000;
 const uint32_t FMQ_SIZE_16M = 0x1000000;
 
-#define CLEAR_KEY_SYSTEM_ID 0xF6D8
-#define FILTER_MAIN_TYPE_BIT_COUNT 32
-#define PROVISION_STR                                      \
-    "{                                                   " \
-    "  \"id\": 21140844,                                 " \
-    "  \"name\": \"Test Title\",                         " \
-    "  \"lowercase_organization_name\": \"Android\",     " \
-    "  \"asset_key\": {                                  " \
-    "  \"encryption_key\": \"nezAr3CHFrmBR9R8Tedotw==\"  " \
-    "  },                                                " \
-    "  \"cas_type\": 1,                                  " \
-    "  \"track_types\": [ ]                              " \
-    "}                                                   "
+#define FILTER_MAIN_TYPE_BIT_COUNT 5
 
-typedef enum {
-    TS_VIDEO0,
-    TS_VIDEO1,
-    TS_AUDIO0,
-    TS_AUDIO1,
-    TS_PES0,
-    TS_PCR0,
-    TS_SECTION0,
-    TS_TS0,
-    TS_RECORD0,
-    FILTER_MAX,
-} Filter;
+// Hardware configs
+static map<string, FrontendConfig> frontendMap;
+static map<string, FilterConfig> filterMap;
+static map<string, DvrConfig> dvrMap;
+static map<string, LnbConfig> lnbMap;
+static map<string, TimeFilterConfig> timeFilterMap;
+static map<string, vector<uint8_t>> diseqcMsgMap;
+static map<string, DescramblerConfig> descramblerMap;
 
-typedef enum {
-    TIMER0,
-    TIMER_MAX,
-} TimeFilter;
+// Hardware and test cases connections
+static LiveBroadcastHardwareConnections live;
+static ScanHardwareConnections scan;
+static DvrPlaybackHardwareConnections playback;
+static DvrRecordHardwareConnections record;
+static DescramblingHardwareConnections descrambling;
+static LnbLiveHardwareConnections lnbLive;
+static LnbRecordHardwareConnections lnbRecord;
+static TimeFilterHardwareConnections timeFilter;
 
-typedef enum {
-    SOURCE,
-    SINK,
-    LINKAGE_DIR,
-} Linkage;
-
-typedef enum {
-    DVBT,
-    DVBS,
-    FRONTEND_MAX,
-} Frontend;
-
-typedef enum {
-    LNB0,
-    LNB_EXTERNAL,
-    LNB_MAX,
-} Lnb;
-
-typedef enum {
-    DISEQC_POWER_ON,
-    DISEQC_MAX,
-} Diseqc;
-
-typedef enum {
-    SCAN_DVBT,
-    SCAN_MAX,
-} FrontendScan;
-
-typedef enum {
-    DVR_RECORD0,
-    DVR_PLAYBACK0,
-    DVR_MAX,
-} Dvr;
-
-typedef enum {
-    DESC_0,
-    DESC_MAX,
-} Descrambler;
-
-struct FilterConfig {
-    uint32_t bufferSize;
-    DemuxFilterType type;
-    DemuxFilterSettings settings;
-    bool getMqDesc;
-
-    bool operator<(const FilterConfig& /*c*/) const { return false; }
-};
-
-struct TimeFilterConfig {
-    bool supportTimeFilter;
-    uint64_t timeStamp;
-};
-
-struct FrontendConfig {
-    bool enable;
-    bool isSoftwareFe;
-    FrontendType type;
-    FrontendSettings settings;
-    vector<FrontendStatusType> tuneStatusTypes;
-    vector<FrontendStatus> expectTuneStatuses;
-};
-
-struct LnbConfig {
-    bool usingLnb;
-    string name;
-    LnbVoltage voltage;
-    LnbTone tone;
-    LnbPosition position;
-};
-
-struct ChannelConfig {
-    int32_t frontendId;
-    int32_t channelId;
-    std::string channelName;
-    DemuxTpid videoPid;
-    DemuxTpid audioPid;
-};
-
-struct DvrConfig {
-    DvrType type;
-    uint32_t bufferSize;
-    DvrSettings settings;
-    string playbackInputFile;
-};
-
-struct DescramblerConfig {
-    uint32_t casSystemId;
-    string provisionStr;
-    vector<uint8_t> hidlPvtData;
-};
-
-static FrontendConfig frontendArray[FILTER_MAX];
-static FrontendConfig frontendScanArray[SCAN_MAX];
-static LnbConfig lnbArray[LNB_MAX];
-static vector<uint8_t> diseqcMsgArray[DISEQC_MAX];
-static ChannelConfig channelArray[FRONTEND_MAX];
-static FilterConfig filterArray[FILTER_MAX];
-static TimeFilterConfig timeFilterArray[TIMER_MAX];
-static DemuxFilterType filterLinkageTypes[LINKAGE_DIR][FILTER_MAIN_TYPE_BIT_COUNT];
-static DvrConfig dvrArray[DVR_MAX];
-static DescramblerConfig descramblerArray[DESC_MAX];
-static vector<string> goldenOutputFiles;
-static int defaultFrontend = DVBT;
-static int defaultScanFrontend = SCAN_DVBT;
-
-/** Configuration array for the frontend tune test */
+/** Config all the frontends that would be used in the tests */
 inline void initFrontendConfig() {
+    // The test will use the internal default fe when default fe is connected to any data flow
+    // without overriding in the xml config.
+    string defaultFeId = "FE_DEFAULT";
     FrontendDvbtSettings dvbtSettings{
             .frequency = 578000,
             .transmissionMode = FrontendDvbtTransmissionMode::AUTO,
             .bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ,
-            .constellation = FrontendDvbtConstellation::AUTO,
-            .hierarchy = FrontendDvbtHierarchy::AUTO,
-            .hpCoderate = FrontendDvbtCoderate::AUTO,
-            .lpCoderate = FrontendDvbtCoderate::AUTO,
-            .guardInterval = FrontendDvbtGuardInterval::AUTO,
             .isHighPriority = true,
-            .standard = FrontendDvbtStandard::T,
     };
-    frontendArray[DVBT].type = FrontendType::DVBT, frontendArray[DVBT].settings.dvbt(dvbtSettings);
+    frontendMap[defaultFeId].type = FrontendType::DVBT;
+    frontendMap[defaultFeId].settings.dvbt(dvbtSettings);
+
     vector<FrontendStatusType> types;
     types.push_back(FrontendStatusType::DEMOD_LOCK);
     FrontendStatus status;
     status.isDemodLocked(true);
     vector<FrontendStatus> statuses;
     statuses.push_back(status);
-    frontendArray[DVBT].tuneStatusTypes = types;
-    frontendArray[DVBT].expectTuneStatuses = statuses;
-    frontendArray[DVBT].isSoftwareFe = true;
-    frontendArray[DVBT].enable = true;
-    frontendArray[DVBS].type = FrontendType::DVBS;
-    frontendArray[DVBS].enable = true;
-    frontendArray[DVBS].isSoftwareFe = true;
+    frontendMap[defaultFeId].tuneStatusTypes = types;
+    frontendMap[defaultFeId].expectTuneStatuses = statuses;
+    frontendMap[defaultFeId].isSoftwareFe = true;
+
+    // Read customized config
+    TunerTestingConfigReader::readFrontendConfig1_0(frontendMap);
 };
 
-/** Configuration array for the frontend scan test */
-inline void initFrontendScanConfig() {
-    frontendScanArray[SCAN_DVBT].type = FrontendType::DVBT;
-    frontendScanArray[SCAN_DVBT].settings.dvbt({
-            .frequency = 578000,
-            .transmissionMode = FrontendDvbtTransmissionMode::MODE_8K,
-            .bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ,
-            .constellation = FrontendDvbtConstellation::AUTO,
-            .hierarchy = FrontendDvbtHierarchy::AUTO,
-            .hpCoderate = FrontendDvbtCoderate::AUTO,
-            .lpCoderate = FrontendDvbtCoderate::AUTO,
-            .guardInterval = FrontendDvbtGuardInterval::AUTO,
-            .isHighPriority = true,
-            .standard = FrontendDvbtStandard::T,
-    });
-};
-
-/** Configuration array for the Lnb test */
-inline void initLnbConfig() {
-    lnbArray[LNB0].usingLnb = true;
-    lnbArray[LNB0].voltage = LnbVoltage::VOLTAGE_12V;
-    lnbArray[LNB0].tone = LnbTone::NONE;
-    lnbArray[LNB0].position = LnbPosition::UNDEFINED;
-    lnbArray[LNB_EXTERNAL].usingLnb = true;
-    lnbArray[LNB_EXTERNAL].name = "default_lnb_external";
-    lnbArray[LNB_EXTERNAL].voltage = LnbVoltage::VOLTAGE_5V;
-    lnbArray[LNB_EXTERNAL].tone = LnbTone::NONE;
-    lnbArray[LNB_EXTERNAL].position = LnbPosition::UNDEFINED;
-};
-
-/** Diseqc messages array for the Lnb test */
-inline void initDiseqcMsg() {
-    diseqcMsgArray[DISEQC_POWER_ON] = {0xE, 0x0, 0x0, 0x0, 0x0, 0x3};
-};
-
-/** Configuration array for the filter test */
 inline void initFilterConfig() {
-    // TS VIDEO filter setting for default implementation testing
-    filterArray[TS_VIDEO0].type.mainType = DemuxFilterMainType::TS;
-    filterArray[TS_VIDEO0].type.subType.tsFilterType(DemuxTsFilterType::VIDEO);
-    filterArray[TS_VIDEO0].bufferSize = FMQ_SIZE_16M;
-    filterArray[TS_VIDEO0].settings.ts().tpid = 256;
-    filterArray[TS_VIDEO0].settings.ts().filterSettings.av({.isPassthrough = false});
-    filterArray[TS_VIDEO1].type.mainType = DemuxFilterMainType::TS;
-    filterArray[TS_VIDEO1].type.subType.tsFilterType(DemuxTsFilterType::VIDEO);
-    filterArray[TS_VIDEO1].bufferSize = FMQ_SIZE_16M;
-    filterArray[TS_VIDEO1].settings.ts().tpid = 256;
-    filterArray[TS_VIDEO1].settings.ts().filterSettings.av({.isPassthrough = false});
-    // TS AUDIO filter setting
-    filterArray[TS_AUDIO0].type.mainType = DemuxFilterMainType::TS;
-    filterArray[TS_AUDIO0].type.subType.tsFilterType(DemuxTsFilterType::AUDIO);
-    filterArray[TS_AUDIO0].bufferSize = FMQ_SIZE_16M;
-    filterArray[TS_AUDIO0].settings.ts().tpid = 256;
-    filterArray[TS_AUDIO0].settings.ts().filterSettings.av({.isPassthrough = false});
-    filterArray[TS_AUDIO1].type.mainType = DemuxFilterMainType::TS;
-    filterArray[TS_AUDIO1].type.subType.tsFilterType(DemuxTsFilterType::AUDIO);
-    filterArray[TS_AUDIO1].bufferSize = FMQ_SIZE_16M;
-    filterArray[TS_AUDIO1].settings.ts().tpid = 257;
-    filterArray[TS_AUDIO1].settings.ts().filterSettings.av({.isPassthrough = false});
-    // TS PES filter setting
-    filterArray[TS_PES0].type.mainType = DemuxFilterMainType::TS;
-    filterArray[TS_PES0].type.subType.tsFilterType(DemuxTsFilterType::PES);
-    filterArray[TS_PES0].bufferSize = FMQ_SIZE_16M;
-    filterArray[TS_PES0].settings.ts().tpid = 256;
-    filterArray[TS_PES0].settings.ts().filterSettings.pesData({
-            .isRaw = false,
-            .streamId = 0xbd,
-    });
-    filterArray[TS_PES0].getMqDesc = true;
-    // TS PCR filter setting
-    filterArray[TS_PCR0].type.mainType = DemuxFilterMainType::TS;
-    filterArray[TS_PCR0].type.subType.tsFilterType(DemuxTsFilterType::PCR);
-    filterArray[TS_PCR0].bufferSize = FMQ_SIZE_16M;
-    filterArray[TS_PCR0].settings.ts().tpid = 256;
-    filterArray[TS_PCR0].settings.ts().filterSettings.noinit();
-    // TS filter setting
-    filterArray[TS_TS0].type.mainType = DemuxFilterMainType::TS;
-    filterArray[TS_TS0].type.subType.tsFilterType(DemuxTsFilterType::TS);
-    filterArray[TS_TS0].bufferSize = FMQ_SIZE_16M;
-    filterArray[TS_TS0].settings.ts().tpid = 256;
-    filterArray[TS_TS0].settings.ts().filterSettings.noinit();
-    // TS SECTION filter setting
-    filterArray[TS_SECTION0].type.mainType = DemuxFilterMainType::TS;
-    filterArray[TS_SECTION0].type.subType.tsFilterType(DemuxTsFilterType::SECTION);
-    filterArray[TS_SECTION0].bufferSize = FMQ_SIZE_16M;
-    filterArray[TS_SECTION0].settings.ts().tpid = 256;
-    filterArray[TS_SECTION0].settings.ts().filterSettings.section({
-            .isRaw = false,
-    });
-    filterArray[TS_SECTION0].getMqDesc = true;
-    // TS RECORD filter setting
-    filterArray[TS_RECORD0].type.mainType = DemuxFilterMainType::TS;
-    filterArray[TS_RECORD0].type.subType.tsFilterType(DemuxTsFilterType::RECORD);
-    filterArray[TS_RECORD0].settings.ts().tpid = 81;
-    filterArray[TS_RECORD0].settings.ts().filterSettings.record({
-            .scIndexType = DemuxRecordScIndexType::NONE,
-    });
+    // The test will use the internal default filter when default filter is connected to any
+    // data flow without overriding in the xml config.
+    string defaultAudioFilterId = "FILTER_AUDIO_DEFAULT";
+    string defaultVideoFilterId = "FILTER_VIDEO_DEFAULT";
 
-    // TS Linkage filter setting
-    filterLinkageTypes[SOURCE][0].mainType = DemuxFilterMainType::TS;
-    filterLinkageTypes[SOURCE][0].subType.tsFilterType(DemuxTsFilterType::TS);
-    filterLinkageTypes[SINK][0] = filterLinkageTypes[SOURCE][0];
-    // MMTP Linkage filter setting
-    filterLinkageTypes[SOURCE][1].mainType = DemuxFilterMainType::MMTP;
-    filterLinkageTypes[SOURCE][1].subType.mmtpFilterType(DemuxMmtpFilterType::AUDIO);
-    filterLinkageTypes[SINK][1] = filterLinkageTypes[SOURCE][1];
-    // IP Linkage filter setting
-    filterLinkageTypes[SOURCE][2].mainType = DemuxFilterMainType::IP;
-    filterLinkageTypes[SOURCE][2].subType.ipFilterType(DemuxIpFilterType::IP);
-    filterLinkageTypes[SINK][2] = filterLinkageTypes[SOURCE][2];
-    // TLV Linkage filter setting
-    filterLinkageTypes[SOURCE][3].mainType = DemuxFilterMainType::TLV;
-    filterLinkageTypes[SOURCE][3].subType.tlvFilterType(DemuxTlvFilterType::TLV);
-    filterLinkageTypes[SINK][3] = filterLinkageTypes[SOURCE][3];
-    // ALP Linkage PTP filter setting
-    filterLinkageTypes[SOURCE][4].mainType = DemuxFilterMainType::ALP;
-    filterLinkageTypes[SOURCE][4].subType.alpFilterType(DemuxAlpFilterType::PTP);
-    filterLinkageTypes[SINK][4] = filterLinkageTypes[SOURCE][4];
+    filterMap[defaultVideoFilterId].type.mainType = DemuxFilterMainType::TS;
+    filterMap[defaultVideoFilterId].type.subType.tsFilterType(DemuxTsFilterType::VIDEO);
+    filterMap[defaultVideoFilterId].bufferSize = FMQ_SIZE_16M;
+    filterMap[defaultVideoFilterId].settings.ts().tpid = 256;
+    filterMap[defaultVideoFilterId].settings.ts().filterSettings.av({.isPassthrough = false});
+
+    filterMap[defaultAudioFilterId].type.mainType = DemuxFilterMainType::TS;
+    filterMap[defaultAudioFilterId].type.subType.tsFilterType(DemuxTsFilterType::AUDIO);
+    filterMap[defaultAudioFilterId].bufferSize = FMQ_SIZE_16M;
+    filterMap[defaultAudioFilterId].settings.ts().tpid = 256;
+    filterMap[defaultAudioFilterId].settings.ts().filterSettings.av({.isPassthrough = false});
+
+    // Read customized config
+    TunerTestingConfigReader::readFilterConfig1_0(filterMap);
 };
 
-/** Configuration array for the timer filter test */
-inline void initTimeFilterConfig() {
-    timeFilterArray[TIMER0].supportTimeFilter = true;
-    timeFilterArray[TIMER0].timeStamp = 1;
-}
-
-/** Configuration array for the dvr test */
+/** Config all the dvrs that would be used in the tests */
 inline void initDvrConfig() {
-    RecordSettings recordSettings{
-            .statusMask = 0xf,
-            .lowThreshold = 0x1000,
-            .highThreshold = 0x07fff,
-            .dataFormat = DataFormat::TS,
-            .packetSize = 188,
-    };
-    dvrArray[DVR_RECORD0].type = DvrType::RECORD;
-    dvrArray[DVR_RECORD0].bufferSize = FMQ_SIZE_4M;
-    dvrArray[DVR_RECORD0].settings.record(recordSettings);
-    PlaybackSettings playbackSettings{
-            .statusMask = 0xf,
-            .lowThreshold = 0x1000,
-            .highThreshold = 0x07fff,
-            .dataFormat = DataFormat::TS,
-            .packetSize = 188,
-    };
-    dvrArray[DVR_PLAYBACK0].type = DvrType::PLAYBACK;
-    dvrArray[DVR_PLAYBACK0].playbackInputFile = "/data/local/tmp/segment000000.ts";
-    dvrArray[DVR_PLAYBACK0].bufferSize = FMQ_SIZE_4M;
-    dvrArray[DVR_PLAYBACK0].settings.playback(playbackSettings);
+    // Read customized config
+    TunerTestingConfigReader::readDvrConfig1_0(dvrMap);
 };
 
-/** Configuration array for the descrambler test */
-inline void initDescramblerConfig() {
-    descramblerArray[DESC_0].casSystemId = CLEAR_KEY_SYSTEM_ID;
-    descramblerArray[DESC_0].provisionStr = PROVISION_STR;
-    descramblerArray[DESC_0].hidlPvtData.resize(256);
+/** Config all the lnbs that would be used in the tests */
+inline void initLnbConfig() {
+    // Read customized config
+    TunerTestingConfigReader::readLnbConfig1_0(lnbMap);
+    TunerTestingConfigReader::readDiseqcMessages(diseqcMsgMap);
 };
+
+/** Config all the time filters that would be used in the tests */
+inline void initTimeFilterConfig() {
+    // Read customized config
+    TunerTestingConfigReader::readTimeFilterConfig1_0(timeFilterMap);
+};
+
+/** Config all the descramblers that would be used in the tests */
+inline void initDescramblerConfig() {
+    // Read customized config
+    TunerTestingConfigReader::readDescramblerConfig1_0(descramblerMap);
+};
+
+/** Read the vendor configurations of which hardware to use for each test cases/data flows */
+inline void connectHardwaresToTestCases() {
+    TunerTestingConfigReader::connectLiveBroadcast(live);
+    TunerTestingConfigReader::connectScan(scan);
+    TunerTestingConfigReader::connectDvrPlayback(playback);
+    TunerTestingConfigReader::connectDvrRecord(record);
+    TunerTestingConfigReader::connectDescrambling(descrambling);
+    TunerTestingConfigReader::connectLnbLive(lnbLive);
+    TunerTestingConfigReader::connectLnbRecord(lnbRecord);
+    TunerTestingConfigReader::connectTimeFilter(timeFilter);
+};
+
+inline bool validateConnections() {
+    bool feIsValid = frontendMap.find(live.frontendId) != frontendMap.end() &&
+                     frontendMap.find(scan.frontendId) != frontendMap.end();
+    feIsValid &= record.support ? frontendMap.find(record.frontendId) != frontendMap.end() : true;
+    feIsValid &= descrambling.support
+                         ? frontendMap.find(descrambling.frontendId) != frontendMap.end()
+                         : true;
+    feIsValid &= lnbLive.support ? frontendMap.find(lnbLive.frontendId) != frontendMap.end() : true;
+    feIsValid &=
+            lnbRecord.support ? frontendMap.find(lnbRecord.frontendId) != frontendMap.end() : true;
+
+    if (!feIsValid) {
+        ALOGW("[vts config] dynamic config fe connection is invalid.");
+        return false;
+    }
+
+    bool dvrIsValid = frontendMap[live.frontendId].isSoftwareFe
+                              ? dvrMap.find(live.dvrSoftwareFeId) != dvrMap.end()
+                              : true;
+    dvrIsValid &= playback.support ? dvrMap.find(playback.dvrId) != dvrMap.end() : true;
+    if (record.support) {
+        if (frontendMap[record.frontendId].isSoftwareFe) {
+            dvrIsValid &= dvrMap.find(record.dvrSoftwareFeId) != dvrMap.end();
+        }
+        dvrIsValid &= dvrMap.find(record.dvrRecordId) != dvrMap.end();
+    }
+    if (descrambling.support && frontendMap[descrambling.frontendId].isSoftwareFe) {
+        dvrIsValid &= dvrMap.find(descrambling.dvrSoftwareFeId) != dvrMap.end();
+    }
+
+    if (!dvrIsValid) {
+        ALOGW("[vts config] dynamic config dvr connection is invalid.");
+        return false;
+    }
+
+    bool filterIsValid = filterMap.find(live.audioFilterId) != filterMap.end() &&
+                         filterMap.find(live.videoFilterId) != filterMap.end();
+    filterIsValid &= playback.support
+                             ? (filterMap.find(playback.audioFilterId) != filterMap.end() &&
+                                filterMap.find(playback.videoFilterId) != filterMap.end())
+                             : true;
+    filterIsValid &=
+            record.support ? filterMap.find(record.recordFilterId) != filterMap.end() : true;
+    filterIsValid &= descrambling.support
+                             ? (filterMap.find(descrambling.audioFilterId) != filterMap.end() &&
+                                filterMap.find(descrambling.videoFilterId) != filterMap.end())
+                             : true;
+    filterIsValid &= lnbLive.support ? (filterMap.find(lnbLive.audioFilterId) != filterMap.end() &&
+                                        filterMap.find(lnbLive.videoFilterId) != filterMap.end())
+                                     : true;
+    filterIsValid &=
+            lnbRecord.support ? filterMap.find(lnbRecord.recordFilterId) != filterMap.end() : true;
+
+    if (!filterIsValid) {
+        ALOGW("[vts config] dynamic config filter connection is invalid.");
+        return false;
+    }
+
+    bool lnbIsValid = lnbLive.support ? lnbMap.find(lnbLive.lnbId) != lnbMap.end() : true;
+    lnbIsValid &= lnbRecord.support ? lnbMap.find(lnbRecord.lnbId) != lnbMap.end() : true;
+
+    if (!lnbIsValid) {
+        ALOGW("[vts config] dynamic config lnb connection is invalid.");
+        return false;
+    }
+
+    bool descramblerIsValid =
+            descrambling.support
+                    ? descramblerMap.find(descrambling.descramblerId) != descramblerMap.end()
+                    : true;
+
+    if (!descramblerIsValid) {
+        ALOGW("[vts config] dynamic config descrambler connection is invalid.");
+        return false;
+    }
+
+    bool diseqcMsgIsValid = true;
+    if (lnbLive.support) {
+        for (auto msgName : lnbLive.diseqcMsgs) {
+            diseqcMsgIsValid &= diseqcMsgMap.find(msgName) != diseqcMsgMap.end();
+        }
+    }
+    if (lnbRecord.support) {
+        for (auto msgName : lnbRecord.diseqcMsgs) {
+            diseqcMsgIsValid &= diseqcMsgMap.find(msgName) != diseqcMsgMap.end();
+        }
+    }
+
+    if (!diseqcMsgIsValid) {
+        ALOGW("[vts config] dynamic config diseqcMsg sender is invalid.");
+        return false;
+    }
+
+    return true;
+}
diff --git a/tv/tuner/1.1/default/Tuner.cpp b/tv/tuner/1.1/default/Tuner.cpp
index 38b2a26..1e940ba 100644
--- a/tv/tuner/1.1/default/Tuner.cpp
+++ b/tv/tuner/1.1/default/Tuner.cpp
@@ -237,6 +237,8 @@
 
     // IP filter can be an MMTP filter's data source.
     caps.linkCaps = {0x00, 0x00, 0x02, 0x00, 0x00};
+    // Support time filter testing
+    caps.bTimeFilter = true;
     _hidl_cb(Result::SUCCESS, caps);
     return Void();
 }
diff --git a/tv/tuner/config/Android.bp b/tv/tuner/config/Android.bp
new file mode 100644
index 0000000..ddbf3a7
--- /dev/null
+++ b/tv/tuner/config/Android.bp
@@ -0,0 +1,31 @@
+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"],
+}
+
+xsd_config {
+    name: "tuner_testing_dynamic_configuration_V1_0",
+    srcs: ["tuner_testing_dynamic_configuration.xsd"],
+    package_name: "android.media.tuner.testing.configuration.V1_0",
+    nullability: true,
+}
+
+xsd_config {
+    name: "tuner_testing_dynamic_configuration_V1_0_enums",
+    srcs: ["tuner_testing_dynamic_configuration.xsd"],
+    package_name: "android.media.tuner.testing.configuration.V1_0",
+    nullability: true,
+    enums_only: true,
+}
+
+xsd_config {
+    name: "tuner_testing_dynamic_configuration_V1_0_parser",
+    srcs: ["tuner_testing_dynamic_configuration.xsd"],
+    package_name: "android.media.tuner.testing.configuration.V1_0",
+    nullability: true,
+    parser_only: true,
+}
diff --git a/tv/tuner/config/OWNERS b/tv/tuner/config/OWNERS
new file mode 100644
index 0000000..1b3d095
--- /dev/null
+++ b/tv/tuner/config/OWNERS
@@ -0,0 +1,4 @@
+nchalko@google.com
+amyjojo@google.com
+shubang@google.com
+quxiangfang@google.com
diff --git a/tv/tuner/config/TunerTestingConfigReader.h b/tv/tuner/config/TunerTestingConfigReader.h
new file mode 100644
index 0000000..90499c4
--- /dev/null
+++ b/tv/tuner/config/TunerTestingConfigReader.h
@@ -0,0 +1,732 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <android_media_tuner_testing_configuration_V1_0.h>
+#include <android_media_tuner_testing_configuration_V1_0_enums.h>
+#include <binder/MemoryDealer.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+
+using namespace std;
+using namespace android::media::tuner::testing::configuration::V1_0;
+
+using android::hardware::tv::tuner::V1_0::DataFormat;
+using android::hardware::tv::tuner::V1_0::DemuxAlpFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxFilterAvSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxIpFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxRecordScIndexType;
+using android::hardware::tv::tuner::V1_0::DemuxTlvFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxTpid;
+using android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+using android::hardware::tv::tuner::V1_0::DvrSettings;
+using android::hardware::tv::tuner::V1_0::DvrType;
+using android::hardware::tv::tuner::V1_0::FrontendDvbsSettings;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtBandwidth;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtCoderate;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtConstellation;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtGuardInterval;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtHierarchy;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtStandard;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtTransmissionMode;
+using android::hardware::tv::tuner::V1_0::FrontendSettings;
+using android::hardware::tv::tuner::V1_0::FrontendStatus;
+using android::hardware::tv::tuner::V1_0::FrontendStatusType;
+using android::hardware::tv::tuner::V1_0::FrontendType;
+using android::hardware::tv::tuner::V1_0::LnbPosition;
+using android::hardware::tv::tuner::V1_0::LnbTone;
+using android::hardware::tv::tuner::V1_0::LnbVoltage;
+using android::hardware::tv::tuner::V1_0::PlaybackSettings;
+using android::hardware::tv::tuner::V1_0::RecordSettings;
+
+const string configFilePath = "/vendor/etc/tuner_vts_config.xml";
+const string emptyHardwareId = "";
+
+#define PROVISION_STR                                      \
+    "{                                                   " \
+    "  \"id\": 21140844,                                 " \
+    "  \"name\": \"Test Title\",                         " \
+    "  \"lowercase_organization_name\": \"Android\",     " \
+    "  \"asset_key\": {                                  " \
+    "  \"encryption_key\": \"nezAr3CHFrmBR9R8Tedotw==\"  " \
+    "  },                                                " \
+    "  \"cas_type\": 1,                                  " \
+    "  \"track_types\": [ ]                              " \
+    "}                                                   "
+
+struct FrontendConfig {
+    bool isSoftwareFe;
+    FrontendType type;
+    FrontendSettings settings;
+    vector<FrontendStatusType> tuneStatusTypes;
+    vector<FrontendStatus> expectTuneStatuses;
+};
+
+struct FilterConfig {
+    uint32_t bufferSize;
+    DemuxFilterType type;
+    DemuxFilterSettings settings;
+    bool getMqDesc;
+
+    bool operator<(const FilterConfig& /*c*/) const { return false; }
+};
+
+struct DvrConfig {
+    DvrType type;
+    uint32_t bufferSize;
+    DvrSettings settings;
+    string playbackInputFile;
+};
+
+struct LnbConfig {
+    string name;
+    LnbVoltage voltage;
+    LnbTone tone;
+    LnbPosition position;
+};
+
+struct TimeFilterConfig {
+    uint64_t timeStamp;
+};
+
+struct DescramblerConfig {
+    uint32_t casSystemId;
+    string provisionStr;
+    vector<uint8_t> hidlPvtData;
+};
+
+struct LiveBroadcastHardwareConnections {
+    string frontendId;
+    string dvrSoftwareFeId;
+    string audioFilterId;
+    string videoFilterId;
+    string sectionFilterId;
+    string pcrFilterId;
+    /* list string of extra filters; */
+};
+
+struct ScanHardwareConnections {
+    string frontendId;
+};
+
+struct DvrPlaybackHardwareConnections {
+    bool support;
+    string frontendId;
+    string dvrId;
+    string audioFilterId;
+    string videoFilterId;
+    string sectionFilterId;
+    /* list string of extra filters; */
+};
+
+struct DvrRecordHardwareConnections {
+    bool support;
+    string frontendId;
+    string dvrRecordId;
+    string dvrSoftwareFeId;
+    string recordFilterId;
+};
+
+struct DescramblingHardwareConnections {
+    bool support;
+    string frontendId;
+    string dvrSoftwareFeId;
+    string audioFilterId;
+    string videoFilterId;
+    string descramblerId;
+    /* list string of extra filters; */
+};
+
+struct LnbLiveHardwareConnections {
+    bool support;
+    string frontendId;
+    string audioFilterId;
+    string videoFilterId;
+    string lnbId;
+    vector<string> diseqcMsgs;
+    /* list string of extra filters; */
+};
+
+struct LnbRecordHardwareConnections {
+    bool support;
+    string frontendId;
+    string dvrRecordId;
+    string recordFilterId;
+    string lnbId;
+    vector<string> diseqcMsgs;
+    /* list string of extra filters; */
+};
+
+struct TimeFilterHardwareConnections {
+    bool support;
+    string timeFilterId;
+};
+
+struct TunerTestingConfigReader {
+  public:
+    static bool checkConfigFileExists() {
+        auto res = read(configFilePath.c_str());
+        if (res == nullopt) {
+            ALOGW("[ConfigReader] Couldn't read /vendor/etc/tuner_vts_config.xml."
+                  "Please check tuner_testing_dynamic_configuration.xsd"
+                  "and sample_tuner_vts_config.xml for more details on how to config Tune VTS.");
+        }
+        return (res != nullopt);
+    }
+
+    static void readFrontendConfig1_0(map<string, FrontendConfig>& frontendMap) {
+        auto hardwareConfig = getHardwareConfig();
+        if (hardwareConfig.hasFrontends()) {
+            // TODO: b/182519645 complete the tune status config
+            vector<FrontendStatusType> types;
+            types.push_back(FrontendStatusType::DEMOD_LOCK);
+            FrontendStatus status;
+            status.isDemodLocked(true);
+            vector<FrontendStatus> statuses;
+            statuses.push_back(status);
+
+            auto frontends = *hardwareConfig.getFirstFrontends();
+            for (auto feConfig : frontends.getFrontend()) {
+                string id = feConfig.getId();
+                if (id.compare(string("FE_DEFAULT")) == 0) {
+                    // overrid default
+                    frontendMap.erase(string("FE_DEFAULT"));
+                }
+                FrontendType type;
+                switch (feConfig.getType()) {
+                    case FrontendTypeEnum::UNDEFINED:
+                        type = FrontendType::UNDEFINED;
+                        break;
+                    // TODO: b/182519645 finish all other frontend settings
+                    case FrontendTypeEnum::ANALOG:
+                        type = FrontendType::ANALOG;
+                        break;
+                    case FrontendTypeEnum::ATSC:
+                        type = FrontendType::ATSC;
+                        break;
+                    case FrontendTypeEnum::ATSC3:
+                        type = FrontendType::ATSC3;
+                        break;
+                    case FrontendTypeEnum::DVBC:
+                        type = FrontendType::DVBC;
+                        break;
+                    case FrontendTypeEnum::DVBS:
+                        type = FrontendType::DVBS;
+                        frontendMap[id].settings.dvbs(readDvbsFrontendSettings(feConfig));
+                        break;
+                    case FrontendTypeEnum::DVBT: {
+                        type = FrontendType::DVBT;
+                        frontendMap[id].settings.dvbt(readDvbtFrontendSettings(feConfig));
+                        break;
+                    }
+                    case FrontendTypeEnum::ISDBS:
+                        type = FrontendType::ISDBS;
+                        break;
+                    case FrontendTypeEnum::ISDBS3:
+                        type = FrontendType::ISDBS3;
+                        break;
+                    case FrontendTypeEnum::ISDBT:
+                        type = FrontendType::ISDBT;
+                        break;
+                    case FrontendTypeEnum::DTMB:
+                        // dtmb will be handled in readFrontendConfig1_1;
+                        continue;
+                    case FrontendTypeEnum::UNKNOWN:
+                        ALOGW("[ConfigReader] invalid frontend type");
+                        return;
+                }
+                frontendMap[id].type = type;
+                frontendMap[id].isSoftwareFe = feConfig.getIsSoftwareFrontend();
+                // TODO: b/182519645 complete the tune status config
+                frontendMap[id].tuneStatusTypes = types;
+                frontendMap[id].expectTuneStatuses = statuses;
+            }
+        }
+    }
+
+    static void readFilterConfig1_0(map<string, FilterConfig>& filterMap) {
+        auto hardwareConfig = getHardwareConfig();
+        if (hardwareConfig.hasFilters()) {
+            auto filters = *hardwareConfig.getFirstFilters();
+            for (auto filterConfig : filters.getFilter()) {
+                string id = filterConfig.getId();
+                if (id.compare(string("FILTER_AUDIO_DEFAULT")) == 0) {
+                    // overrid default
+                    filterMap.erase(string("FILTER_AUDIO_DEFAULT"));
+                }
+                if (id.compare(string("FILTER_VIDEO_DEFAULT")) == 0) {
+                    // overrid default
+                    filterMap.erase(string("FILTER_VIDEO_DEFAULT"));
+                }
+
+                DemuxFilterType type;
+                DemuxFilterSettings settings;
+                if (!readFilterTypeAndSettings(filterConfig, type, settings)) {
+                    ALOGW("[ConfigReader] invalid filter type");
+                    return;
+                }
+                filterMap[id].type = type;
+                filterMap[id].bufferSize = filterConfig.getBufferSize();
+                filterMap[id].getMqDesc = filterConfig.getUseFMQ();
+                filterMap[id].settings = settings;
+            }
+        }
+    }
+
+    static void readDvrConfig1_0(map<string, DvrConfig>& dvrMap) {
+        auto hardwareConfig = getHardwareConfig();
+        if (hardwareConfig.hasDvrs()) {
+            auto dvrs = *hardwareConfig.getFirstDvrs();
+            for (auto dvrConfig : dvrs.getDvr()) {
+                string id = dvrConfig.getId();
+                DvrType type;
+                switch (dvrConfig.getType()) {
+                    case DvrTypeEnum::PLAYBACK:
+                        type = DvrType::PLAYBACK;
+                        dvrMap[id].settings.playback(readPlaybackSettings(dvrConfig));
+                        break;
+                    case DvrTypeEnum::RECORD:
+                        type = DvrType::RECORD;
+                        dvrMap[id].settings.record(readRecordSettings(dvrConfig));
+                        break;
+                    case DvrTypeEnum::UNKNOWN:
+                        ALOGW("[ConfigReader] invalid DVR type");
+                        return;
+                }
+                dvrMap[id].type = type;
+                dvrMap[id].bufferSize = static_cast<uint32_t>(dvrConfig.getBufferSize());
+                if (dvrConfig.hasInputFilePath()) {
+                    dvrMap[id].playbackInputFile = dvrConfig.getInputFilePath();
+                }
+            }
+        }
+    }
+
+    static void readLnbConfig1_0(map<string, LnbConfig>& lnbMap) {
+        auto hardwareConfig = getHardwareConfig();
+        if (hardwareConfig.hasLnbs()) {
+            auto lnbs = *hardwareConfig.getFirstLnbs();
+            for (auto lnbConfig : lnbs.getLnb()) {
+                string id = lnbConfig.getId();
+                if (lnbConfig.hasName()) {
+                    lnbMap[id].name = lnbConfig.getName();
+                } else {
+                    lnbMap[id].name = emptyHardwareId;
+                }
+                lnbMap[id].voltage = static_cast<LnbVoltage>(lnbConfig.getVoltage());
+                lnbMap[id].tone = static_cast<LnbTone>(lnbConfig.getTone());
+                lnbMap[id].position = static_cast<LnbPosition>(lnbConfig.getPosition());
+            }
+        }
+    }
+
+    static void readDescramblerConfig1_0(map<string, DescramblerConfig>& descramblerMap) {
+        auto hardwareConfig = getHardwareConfig();
+        if (hardwareConfig.hasDescramblers()) {
+            auto descramblers = *hardwareConfig.getFirstDescramblers();
+            for (auto descramblerConfig : descramblers.getDescrambler()) {
+                string id = descramblerConfig.getId();
+                descramblerMap[id].casSystemId =
+                        static_cast<uint32_t>(descramblerConfig.getCasSystemId());
+                if (descramblerConfig.hasProvisionStr()) {
+                    descramblerMap[id].provisionStr = descramblerConfig.getProvisionStr();
+                } else {
+                    descramblerMap[id].provisionStr = PROVISION_STR;
+                }
+                if (descramblerConfig.hasSesstionPrivatData()) {
+                    auto privateData = descramblerConfig.getSesstionPrivatData();
+                    int size = privateData.size();
+                    descramblerMap[id].hidlPvtData.resize(size);
+                    memcpy(descramblerMap[id].hidlPvtData.data(), privateData.data(), size);
+                } else {
+                    descramblerMap[id].hidlPvtData.resize(256);
+                }
+            }
+        }
+    }
+
+    static void readDiseqcMessages(map<string, vector<uint8_t>>& diseqcMsgMap) {
+        auto hardwareConfig = getHardwareConfig();
+        if (hardwareConfig.hasDiseqcMessages()) {
+            auto msgs = *hardwareConfig.getFirstDiseqcMessages();
+            for (auto msgConfig : msgs.getDiseqcMessage()) {
+                string name = msgConfig.getMsgName();
+                for (uint8_t atom : msgConfig.getMsgBody()) {
+                    diseqcMsgMap[name].push_back(atom);
+                }
+            }
+        }
+    }
+
+    static void readTimeFilterConfig1_0(map<string, TimeFilterConfig>& timeFilterMap) {
+        auto hardwareConfig = getHardwareConfig();
+        if (hardwareConfig.hasTimeFilters()) {
+            auto timeFilters = *hardwareConfig.getFirstTimeFilters();
+            for (auto timeFilterConfig : timeFilters.getTimeFilter()) {
+                string id = timeFilterConfig.getId();
+                timeFilterMap[id].timeStamp =
+                        static_cast<uint64_t>(timeFilterConfig.getTimeStamp());
+            }
+        }
+    }
+
+    static void connectLiveBroadcast(LiveBroadcastHardwareConnections& live) {
+        auto liveConfig = *getDataFlowConfiguration().getFirstClearLiveBroadcast();
+        live.frontendId = liveConfig.getFrontendConnection();
+
+        live.audioFilterId = liveConfig.getAudioFilterConnection();
+        live.videoFilterId = liveConfig.getVideoFilterConnection();
+        if (liveConfig.hasPcrFilterConnection()) {
+            live.pcrFilterId = liveConfig.getPcrFilterConnection();
+        } else {
+            live.pcrFilterId = emptyHardwareId;
+        }
+        if (liveConfig.hasSectionFilterConnection()) {
+            live.sectionFilterId = liveConfig.getSectionFilterConnection();
+        } else {
+            live.sectionFilterId = emptyHardwareId;
+        }
+        if (liveConfig.hasDvrSoftwareFeConnection()) {
+            live.dvrSoftwareFeId = liveConfig.getDvrSoftwareFeConnection();
+        }
+    }
+
+    static void connectScan(ScanHardwareConnections& scan) {
+        auto scanConfig = getDataFlowConfiguration().getFirstScan();
+        scan.frontendId = scanConfig->getFrontendConnection();
+    }
+
+    static void connectDvrPlayback(DvrPlaybackHardwareConnections& playback) {
+        auto dataFlow = getDataFlowConfiguration();
+        if (dataFlow.hasDvrPlayback()) {
+            playback.support = true;
+        } else {
+            return;
+        }
+        auto playbackConfig = *dataFlow.getFirstDvrPlayback();
+        playback.dvrId = playbackConfig.getDvrConnection();
+        playback.audioFilterId = playbackConfig.getAudioFilterConnection();
+        playback.videoFilterId = playbackConfig.getVideoFilterConnection();
+        if (playbackConfig.hasSectionFilterConnection()) {
+            playback.sectionFilterId = playbackConfig.getSectionFilterConnection();
+        } else {
+            playback.sectionFilterId = emptyHardwareId;
+        }
+    }
+
+    static void connectDvrRecord(DvrRecordHardwareConnections& record) {
+        auto dataFlow = getDataFlowConfiguration();
+        if (dataFlow.hasDvrRecord()) {
+            record.support = true;
+        } else {
+            return;
+        }
+        auto recordConfig = *dataFlow.getFirstDvrRecord();
+        record.frontendId = recordConfig.getFrontendConnection();
+        record.recordFilterId = recordConfig.getRecordFilterConnection();
+        record.dvrRecordId = recordConfig.getDvrRecordConnection();
+        if (recordConfig.hasDvrSoftwareFeConnection()) {
+            record.dvrSoftwareFeId = recordConfig.getDvrSoftwareFeConnection();
+        }
+    }
+
+    static void connectDescrambling(DescramblingHardwareConnections& descrambling) {
+        auto dataFlow = getDataFlowConfiguration();
+        if (dataFlow.hasDescrambling()) {
+            descrambling.support = true;
+        } else {
+            return;
+        }
+        auto descConfig = *dataFlow.getFirstDescrambling();
+        descrambling.frontendId = descConfig.getFrontendConnection();
+        descrambling.descramblerId = descConfig.getDescramblerConnection();
+        descrambling.audioFilterId = descConfig.getAudioFilterConnection();
+        descrambling.videoFilterId = descConfig.getVideoFilterConnection();
+        if (descConfig.hasDvrSoftwareFeConnection()) {
+            descrambling.dvrSoftwareFeId = descConfig.getDvrSoftwareFeConnection();
+        }
+    }
+
+    static void connectLnbLive(LnbLiveHardwareConnections& lnbLive) {
+        auto dataFlow = getDataFlowConfiguration();
+        if (dataFlow.hasLnbLive()) {
+            lnbLive.support = true;
+        } else {
+            return;
+        }
+        auto lnbLiveConfig = *dataFlow.getFirstLnbLive();
+        lnbLive.frontendId = lnbLiveConfig.getFrontendConnection();
+        lnbLive.audioFilterId = lnbLiveConfig.getAudioFilterConnection();
+        lnbLive.videoFilterId = lnbLiveConfig.getVideoFilterConnection();
+        lnbLive.lnbId = lnbLiveConfig.getLnbConnection();
+        if (lnbLiveConfig.hasDiseqcMsgSender()) {
+            for (auto msgName : lnbLiveConfig.getDiseqcMsgSender()) {
+                lnbLive.diseqcMsgs.push_back(msgName);
+            }
+        }
+    }
+
+    static void connectLnbRecord(LnbRecordHardwareConnections& lnbRecord) {
+        auto dataFlow = getDataFlowConfiguration();
+        if (dataFlow.hasLnbRecord()) {
+            lnbRecord.support = true;
+        } else {
+            return;
+        }
+        auto lnbRecordConfig = *dataFlow.getFirstLnbRecord();
+        lnbRecord.frontendId = lnbRecordConfig.getFrontendConnection();
+        lnbRecord.recordFilterId = lnbRecordConfig.getRecordFilterConnection();
+        lnbRecord.dvrRecordId = lnbRecordConfig.getDvrRecordConnection();
+        lnbRecord.lnbId = lnbRecordConfig.getLnbConnection();
+        if (lnbRecordConfig.hasDiseqcMsgSender()) {
+            for (auto msgName : lnbRecordConfig.getDiseqcMsgSender()) {
+                lnbRecord.diseqcMsgs.push_back(msgName);
+            }
+        }
+    }
+
+    static void connectTimeFilter(TimeFilterHardwareConnections& timeFilter) {
+        auto dataFlow = getDataFlowConfiguration();
+        if (dataFlow.hasTimeFilter()) {
+            timeFilter.support = true;
+        } else {
+            return;
+        }
+        auto timeFilterConfig = *dataFlow.getFirstTimeFilter();
+        timeFilter.timeFilterId = timeFilterConfig.getTimeFilterConnection();
+    }
+
+  private:
+    static FrontendDvbtSettings readDvbtFrontendSettings(Frontend feConfig) {
+        ALOGW("[ConfigReader] fe type is dvbt");
+        FrontendDvbtSettings dvbtSettings{
+                .frequency = (uint32_t)feConfig.getFrequency(),
+        };
+        if (!feConfig.hasDvbtFrontendSettings_optional()) {
+            ALOGW("[ConfigReader] no more dvbt settings");
+            return dvbtSettings;
+        }
+        dvbtSettings.transmissionMode = static_cast<FrontendDvbtTransmissionMode>(
+                feConfig.getFirstDvbtFrontendSettings_optional()->getTransmissionMode());
+        dvbtSettings.bandwidth = static_cast<FrontendDvbtBandwidth>(
+                feConfig.getFirstDvbtFrontendSettings_optional()->getBandwidth());
+        dvbtSettings.isHighPriority =
+                feConfig.getFirstDvbtFrontendSettings_optional()->getIsHighPriority();
+        return dvbtSettings;
+    }
+
+    static FrontendDvbsSettings readDvbsFrontendSettings(Frontend feConfig) {
+        ALOGW("[ConfigReader] fe type is dvbs");
+        FrontendDvbsSettings dvbsSettings{
+                .frequency = (uint32_t)feConfig.getFrequency(),
+        };
+        if (!feConfig.hasDvbsFrontendSettings_optional()) {
+            ALOGW("[ConfigReader] no more dvbs settings");
+            return dvbsSettings;
+        }
+        dvbsSettings.symbolRate = static_cast<uint32_t>(
+                feConfig.getFirstDvbsFrontendSettings_optional()->getSymbolRate());
+        dvbsSettings.inputStreamId = static_cast<uint32_t>(
+                feConfig.getFirstDvbsFrontendSettings_optional()->getInputStreamId());
+        return dvbsSettings;
+    }
+
+    static bool readFilterTypeAndSettings(Filter filterConfig, DemuxFilterType& type,
+                                          DemuxFilterSettings& settings) {
+        auto mainType = filterConfig.getMainType();
+        auto subType = filterConfig.getSubType();
+        uint32_t pid = static_cast<uint32_t>(filterConfig.getPid());
+        switch (mainType) {
+            case FilterMainTypeEnum::TS: {
+                ALOGW("[ConfigReader] filter main type is ts");
+                type.mainType = DemuxFilterMainType::TS;
+                switch (subType) {
+                    case FilterSubTypeEnum::UNDEFINED:
+                        break;
+                    case FilterSubTypeEnum::SECTION:
+                        type.subType.tsFilterType(DemuxTsFilterType::SECTION);
+                        settings.ts().filterSettings.section(
+                                readSectionFilterSettings(filterConfig));
+                        break;
+                    case FilterSubTypeEnum::PES:
+                        // TODO: b/182519645 support all the filter settings
+                        /*settings.ts().filterSettings.pesData(
+                                getPesFilterSettings(filterConfig));*/
+                        type.subType.tsFilterType(DemuxTsFilterType::PES);
+                        break;
+                    case FilterSubTypeEnum::TS:
+                        type.subType.tsFilterType(DemuxTsFilterType::TS);
+                        settings.ts().filterSettings.noinit();
+                        break;
+                    case FilterSubTypeEnum::PCR:
+                        type.subType.tsFilterType(DemuxTsFilterType::PCR);
+                        settings.ts().filterSettings.noinit();
+                        break;
+                    case FilterSubTypeEnum::TEMI:
+                        type.subType.tsFilterType(DemuxTsFilterType::TEMI);
+                        settings.ts().filterSettings.noinit();
+                        break;
+                    case FilterSubTypeEnum::AUDIO:
+                        type.subType.tsFilterType(DemuxTsFilterType::AUDIO);
+                        settings.ts().filterSettings.av(readAvFilterSettings(filterConfig));
+                        break;
+                    case FilterSubTypeEnum::VIDEO:
+                        type.subType.tsFilterType(DemuxTsFilterType::VIDEO);
+                        settings.ts().filterSettings.av(readAvFilterSettings(filterConfig));
+                        break;
+                    case FilterSubTypeEnum::RECORD:
+                        type.subType.tsFilterType(DemuxTsFilterType::RECORD);
+                        settings.ts().filterSettings.record(readRecordFilterSettings(filterConfig));
+                        break;
+                    default:
+                        ALOGW("[ConfigReader] ts subtype is not supported");
+                        return false;
+                }
+                settings.ts().tpid = pid;
+                break;
+            }
+            case FilterMainTypeEnum::MMTP: {
+                ALOGW("[ConfigReader] filter main type is mmtp");
+                type.mainType = DemuxFilterMainType::MMTP;
+                switch (subType) {
+                    case FilterSubTypeEnum::UNDEFINED:
+                        break;
+                    case FilterSubTypeEnum::SECTION:
+                        type.subType.mmtpFilterType(DemuxMmtpFilterType::SECTION);
+                        settings.mmtp().filterSettings.section(
+                                readSectionFilterSettings(filterConfig));
+                        break;
+                    case FilterSubTypeEnum::PES:
+                        type.subType.mmtpFilterType(DemuxMmtpFilterType::PES);
+                        // TODO: b/182519645 support all the filter settings
+                        /*settings.mmtp().filterSettings.pesData(
+                                getPesFilterSettings(filterConfig));*/
+                        break;
+                    case FilterSubTypeEnum::MMTP:
+                        type.subType.mmtpFilterType(DemuxMmtpFilterType::MMTP);
+                        settings.mmtp().filterSettings.noinit();
+                        break;
+                    case FilterSubTypeEnum::AUDIO:
+                        type.subType.mmtpFilterType(DemuxMmtpFilterType::AUDIO);
+                        settings.mmtp().filterSettings.av(readAvFilterSettings(filterConfig));
+                        break;
+                    case FilterSubTypeEnum::VIDEO:
+                        settings.mmtp().filterSettings.av(readAvFilterSettings(filterConfig));
+                        break;
+                    case FilterSubTypeEnum::RECORD:
+                        type.subType.mmtpFilterType(DemuxMmtpFilterType::RECORD);
+                        settings.mmtp().filterSettings.record(
+                                readRecordFilterSettings(filterConfig));
+                        break;
+                    case FilterSubTypeEnum::DOWNLOAD:
+                        type.subType.mmtpFilterType(DemuxMmtpFilterType::DOWNLOAD);
+                        // TODO: b/182519645 support all the filter settings
+                        /*settings.mmtp().filterSettings.download(
+                                getDownloadFilterSettings(filterConfig));*/
+                        break;
+                    default:
+                        ALOGW("[ConfigReader] mmtp subtype is not supported");
+                        return false;
+                }
+                settings.mmtp().mmtpPid = pid;
+                break;
+            }
+            default:
+                // TODO: b/182519645 support all the filter configs
+                ALOGW("[ConfigReader] filter main type is not supported in dynamic config");
+                return false;
+        }
+        return true;
+    }
+
+    static DemuxFilterSectionSettings readSectionFilterSettings(Filter filterConfig) {
+        DemuxFilterSectionSettings settings;
+        if (!filterConfig.hasSectionFilterSettings_optional()) {
+            return settings;
+        }
+        auto section = filterConfig.getFirstSectionFilterSettings_optional();
+        settings.isCheckCrc = section->getIsCheckCrc();
+        settings.isRepeat = section->getIsRepeat();
+        settings.isRaw = section->getIsRaw();
+        return settings;
+    }
+
+    static DemuxFilterAvSettings readAvFilterSettings(Filter filterConfig) {
+        DemuxFilterAvSettings settings;
+        if (!filterConfig.hasAvFilterSettings_optional()) {
+            return settings;
+        }
+        auto av = filterConfig.getFirstAvFilterSettings_optional();
+        settings.isPassthrough = av->getIsPassthrough();
+        return settings;
+    }
+
+    static DemuxFilterRecordSettings readRecordFilterSettings(Filter filterConfig) {
+        DemuxFilterRecordSettings settings;
+        if (!filterConfig.hasRecordFilterSettings_optional()) {
+            return settings;
+        }
+        auto record = filterConfig.getFirstRecordFilterSettings_optional();
+        settings.tsIndexMask = static_cast<uint32_t>(record->getTsIndexMask());
+        settings.scIndexType = static_cast<DemuxRecordScIndexType>(record->getScIndexType());
+        return settings;
+    }
+
+    static PlaybackSettings readPlaybackSettings(Dvr dvrConfig) {
+        ALOGW("[ConfigReader] dvr type is playback");
+        PlaybackSettings playbackSettings{
+                .statusMask = static_cast<uint8_t>(dvrConfig.getStatusMask()),
+                .lowThreshold = static_cast<uint32_t>(dvrConfig.getLowThreshold()),
+                .highThreshold = static_cast<uint32_t>(dvrConfig.getHighThreshold()),
+                .dataFormat = static_cast<DataFormat>(dvrConfig.getDataFormat()),
+                .packetSize = static_cast<uint8_t>(dvrConfig.getPacketSize()),
+        };
+        return playbackSettings;
+    }
+
+    static RecordSettings readRecordSettings(Dvr dvrConfig) {
+        ALOGW("[ConfigReader] dvr type is record");
+        RecordSettings recordSettings{
+                .statusMask = static_cast<uint8_t>(dvrConfig.getStatusMask()),
+                .lowThreshold = static_cast<uint32_t>(dvrConfig.getLowThreshold()),
+                .highThreshold = static_cast<uint32_t>(dvrConfig.getHighThreshold()),
+                .dataFormat = static_cast<DataFormat>(dvrConfig.getDataFormat()),
+                .packetSize = static_cast<uint8_t>(dvrConfig.getPacketSize()),
+        };
+        return recordSettings;
+    }
+
+    static TunerConfiguration getTunerConfig() { return *read(configFilePath.c_str()); }
+
+    static HardwareConfiguration getHardwareConfig() {
+        return *getTunerConfig().getFirstHardwareConfiguration();
+    }
+
+    static DataFlowConfiguration getDataFlowConfiguration() {
+        return *getTunerConfig().getFirstDataFlowConfiguration();
+    }
+};
diff --git a/tv/tuner/config/api/current.txt b/tv/tuner/config/api/current.txt
new file mode 100644
index 0000000..4255a60
--- /dev/null
+++ b/tv/tuner/config/api/current.txt
@@ -0,0 +1,433 @@
+// Signature format: 2.0
+package android.media.tuner.testing.configuration.V1_0 {
+
+  public class AvFilterSettings {
+    ctor public AvFilterSettings();
+    method @Nullable public boolean getIsPassthrough();
+    method public void setIsPassthrough(@Nullable boolean);
+  }
+
+  public class DataFlowConfiguration {
+    ctor public DataFlowConfiguration();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.ClearLiveBroadcast getClearLiveBroadcast();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.Descrambling getDescrambling();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.DvrPlayback getDvrPlayback();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.DvrRecord getDvrRecord();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.LnbLive getLnbLive();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.LnbRecord getLnbRecord();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.Scan getScan();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.TimeFilter getTimeFilter();
+    method public void setClearLiveBroadcast(@Nullable android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.ClearLiveBroadcast);
+    method public void setDescrambling(@Nullable android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.Descrambling);
+    method public void setDvrPlayback(@Nullable android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.DvrPlayback);
+    method public void setDvrRecord(@Nullable android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.DvrRecord);
+    method public void setLnbLive(@Nullable android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.LnbLive);
+    method public void setLnbRecord(@Nullable android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.LnbRecord);
+    method public void setScan(@Nullable android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.Scan);
+    method public void setTimeFilter(@Nullable android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.TimeFilter);
+  }
+
+  public static class DataFlowConfiguration.ClearLiveBroadcast {
+    ctor public DataFlowConfiguration.ClearLiveBroadcast();
+    method @Nullable public String getAudioFilterConnection();
+    method @Nullable public String getDvrSoftwareFeConnection();
+    method @Nullable public String getFrontendConnection();
+    method @Nullable public String getPcrFilterConnection();
+    method @Nullable public String getSectionFilterConnection();
+    method @Nullable public String getVideoFilterConnection();
+    method public void setAudioFilterConnection(@Nullable String);
+    method public void setDvrSoftwareFeConnection(@Nullable String);
+    method public void setFrontendConnection(@Nullable String);
+    method public void setPcrFilterConnection(@Nullable String);
+    method public void setSectionFilterConnection(@Nullable String);
+    method public void setVideoFilterConnection(@Nullable String);
+  }
+
+  public static class DataFlowConfiguration.Descrambling {
+    ctor public DataFlowConfiguration.Descrambling();
+    method @Nullable public String getAudioFilterConnection();
+    method @Nullable public String getDescramblerConnection();
+    method @Nullable public String getDvrSoftwareFeConnection();
+    method @Nullable public String getFrontendConnection();
+    method @Nullable public String getVideoFilterConnection();
+    method public void setAudioFilterConnection(@Nullable String);
+    method public void setDescramblerConnection(@Nullable String);
+    method public void setDvrSoftwareFeConnection(@Nullable String);
+    method public void setFrontendConnection(@Nullable String);
+    method public void setVideoFilterConnection(@Nullable String);
+  }
+
+  public static class DataFlowConfiguration.DvrPlayback {
+    ctor public DataFlowConfiguration.DvrPlayback();
+    method @Nullable public String getAudioFilterConnection();
+    method @Nullable public String getDvrConnection();
+    method @Nullable public String getSectionFilterConnection();
+    method @Nullable public String getVideoFilterConnection();
+    method public void setAudioFilterConnection(@Nullable String);
+    method public void setDvrConnection(@Nullable String);
+    method public void setSectionFilterConnection(@Nullable String);
+    method public void setVideoFilterConnection(@Nullable String);
+  }
+
+  public static class DataFlowConfiguration.DvrRecord {
+    ctor public DataFlowConfiguration.DvrRecord();
+    method @Nullable public String getDvrRecordConnection();
+    method @Nullable public String getDvrSoftwareFeConnection();
+    method @Nullable public String getFrontendConnection();
+    method @Nullable public String getRecordFilterConnection();
+    method public void setDvrRecordConnection(@Nullable String);
+    method public void setDvrSoftwareFeConnection(@Nullable String);
+    method public void setFrontendConnection(@Nullable String);
+    method public void setRecordFilterConnection(@Nullable String);
+  }
+
+  public static class DataFlowConfiguration.LnbLive {
+    ctor public DataFlowConfiguration.LnbLive();
+    method @Nullable public String getAudioFilterConnection();
+    method @Nullable public java.util.List<java.lang.String> getDiseqcMsgSender();
+    method @Nullable public String getFrontendConnection();
+    method @Nullable public String getLnbConnection();
+    method @Nullable public String getVideoFilterConnection();
+    method public void setAudioFilterConnection(@Nullable String);
+    method public void setDiseqcMsgSender(@Nullable java.util.List<java.lang.String>);
+    method public void setFrontendConnection(@Nullable String);
+    method public void setLnbConnection(@Nullable String);
+    method public void setVideoFilterConnection(@Nullable String);
+  }
+
+  public static class DataFlowConfiguration.LnbRecord {
+    ctor public DataFlowConfiguration.LnbRecord();
+    method @Nullable public java.util.List<java.lang.String> getDiseqcMsgSender();
+    method @Nullable public String getDvrRecordConnection();
+    method @Nullable public String getFrontendConnection();
+    method @Nullable public String getLnbConnection();
+    method @Nullable public String getRecordFilterConnection();
+    method public void setDiseqcMsgSender(@Nullable java.util.List<java.lang.String>);
+    method public void setDvrRecordConnection(@Nullable String);
+    method public void setFrontendConnection(@Nullable String);
+    method public void setLnbConnection(@Nullable String);
+    method public void setRecordFilterConnection(@Nullable String);
+  }
+
+  public static class DataFlowConfiguration.Scan {
+    ctor public DataFlowConfiguration.Scan();
+    method @Nullable public String getFrontendConnection();
+    method public void setFrontendConnection(@Nullable String);
+  }
+
+  public static class DataFlowConfiguration.TimeFilter {
+    ctor public DataFlowConfiguration.TimeFilter();
+    method @Nullable public String getTimeFilterConnection();
+    method public void setTimeFilterConnection(@Nullable String);
+  }
+
+  public class Descrambler {
+    ctor public Descrambler();
+    method @Nullable public java.math.BigInteger getCasSystemId();
+    method @Nullable public String getId();
+    method @Nullable public String getProvisionStr();
+    method @Nullable public java.util.List<java.lang.Short> getSesstionPrivatData();
+    method public void setCasSystemId(@Nullable java.math.BigInteger);
+    method public void setId(@Nullable String);
+    method public void setProvisionStr(@Nullable String);
+    method public void setSesstionPrivatData(@Nullable java.util.List<java.lang.Short>);
+  }
+
+  public class DiseqcMessage {
+    ctor public DiseqcMessage();
+    method @Nullable public java.util.List<java.lang.Short> getMsgBody();
+    method @Nullable public String getMsgName();
+    method public void setMsgBody(@Nullable java.util.List<java.lang.Short>);
+    method public void setMsgName(@Nullable String);
+  }
+
+  public class DvbsFrontendSettings {
+    ctor public DvbsFrontendSettings();
+    method @Nullable public java.math.BigInteger getInputStreamId();
+    method @Nullable public java.math.BigInteger getSymbolRate();
+    method public void setInputStreamId(@Nullable java.math.BigInteger);
+    method public void setSymbolRate(@Nullable java.math.BigInteger);
+  }
+
+  public class DvbtFrontendSettings {
+    ctor public DvbtFrontendSettings();
+    method @Nullable public java.math.BigInteger getBandwidth();
+    method @Nullable public java.math.BigInteger getIsHighPriority();
+    method @Nullable public java.math.BigInteger getTransmissionMode();
+    method public void setBandwidth(@Nullable java.math.BigInteger);
+    method public void setIsHighPriority(@Nullable java.math.BigInteger);
+    method public void setTransmissionMode(@Nullable java.math.BigInteger);
+  }
+
+  public class Dvr {
+    ctor public Dvr();
+    method @Nullable public java.math.BigInteger getBufferSize();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.DvrDataFormatEnum getDataFormat();
+    method @Nullable public java.math.BigInteger getHighThreshold();
+    method @Nullable public String getId();
+    method @Nullable public String getInputFilePath();
+    method @Nullable public java.math.BigInteger getLowThreshold();
+    method @Nullable public java.math.BigInteger getPacketSize();
+    method @Nullable public java.math.BigInteger getStatusMask();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.DvrTypeEnum getType();
+    method public void setBufferSize(@Nullable java.math.BigInteger);
+    method public void setDataFormat(@Nullable android.media.tuner.testing.configuration.V1_0.DvrDataFormatEnum);
+    method public void setHighThreshold(@Nullable java.math.BigInteger);
+    method public void setId(@Nullable String);
+    method public void setInputFilePath(@Nullable String);
+    method public void setLowThreshold(@Nullable java.math.BigInteger);
+    method public void setPacketSize(@Nullable java.math.BigInteger);
+    method public void setStatusMask(@Nullable java.math.BigInteger);
+    method public void setType(@Nullable android.media.tuner.testing.configuration.V1_0.DvrTypeEnum);
+  }
+
+  public enum DvrDataFormatEnum {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.DvrDataFormatEnum ES;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.DvrDataFormatEnum PES;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.DvrDataFormatEnum SHV_TLV;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.DvrDataFormatEnum TS;
+  }
+
+  public enum DvrStatusEnum {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.DvrStatusEnum DATA_READY;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.DvrStatusEnum HIGH_WATER;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.DvrStatusEnum LOW_WATER;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.DvrStatusEnum OVERFLOW;
+  }
+
+  public enum DvrTypeEnum {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.DvrTypeEnum PLAYBACK;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.DvrTypeEnum RECORD;
+  }
+
+  public class Filter {
+    ctor public Filter();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.AvFilterSettings getAvFilterSettings_optional();
+    method @Nullable public java.math.BigInteger getBufferSize();
+    method @Nullable public String getId();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.FilterMainTypeEnum getMainType();
+    method @Nullable public java.math.BigInteger getPid();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.RecordFilterSettings getRecordFilterSettings_optional();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.SectionFilterSettings getSectionFilterSettings_optional();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum getSubType();
+    method @Nullable public boolean getUseFMQ();
+    method public void setAvFilterSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.AvFilterSettings);
+    method public void setBufferSize(@Nullable java.math.BigInteger);
+    method public void setId(@Nullable String);
+    method public void setMainType(@Nullable android.media.tuner.testing.configuration.V1_0.FilterMainTypeEnum);
+    method public void setPid(@Nullable java.math.BigInteger);
+    method public void setRecordFilterSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.RecordFilterSettings);
+    method public void setSectionFilterSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.SectionFilterSettings);
+    method public void setSubType(@Nullable android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum);
+    method public void setUseFMQ(@Nullable boolean);
+  }
+
+  public enum FilterMainTypeEnum {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterMainTypeEnum MMTP;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterMainTypeEnum TS;
+  }
+
+  public enum FilterSubTypeEnum {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum AUDIO;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum DOWNLOAD;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum MMTP;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum PCR;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum PES;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum RECORD;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum SECTION;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum TEMI;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum TS;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum UNDEFINED;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum VIDEO;
+  }
+
+  public class Frontend {
+    ctor public Frontend();
+    method @Nullable public java.math.BigInteger getConnectToCicamId();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.DvbsFrontendSettings getDvbsFrontendSettings_optional();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.DvbtFrontendSettings getDvbtFrontendSettings_optional();
+    method @Nullable public java.math.BigInteger getEndFrequency();
+    method @Nullable public java.math.BigInteger getFrequency();
+    method @Nullable public String getId();
+    method @Nullable public boolean getIsSoftwareFrontend();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum getType();
+    method public void setConnectToCicamId(@Nullable java.math.BigInteger);
+    method public void setDvbsFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.DvbsFrontendSettings);
+    method public void setDvbtFrontendSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.DvbtFrontendSettings);
+    method public void setEndFrequency(@Nullable java.math.BigInteger);
+    method public void setFrequency(@Nullable java.math.BigInteger);
+    method public void setId(@Nullable String);
+    method public void setIsSoftwareFrontend(@Nullable boolean);
+    method public void setType(@Nullable android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum);
+  }
+
+  public enum FrontendTypeEnum {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum ANALOG;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum ATSC;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum ATSC3;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum DTMB;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum DVBC;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum DVBS;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum DVBT;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum ISDBS;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum ISDBS3;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum ISDBT;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.FrontendTypeEnum UNDEFINED;
+  }
+
+  public class HardwareConfiguration {
+    ctor public HardwareConfiguration();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.Descramblers getDescramblers();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.DiseqcMessages getDiseqcMessages();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.Dvrs getDvrs();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.Filters getFilters();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.Frontends getFrontends();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.Lnbs getLnbs();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.TimeFilters getTimeFilters();
+    method public void setDescramblers(@Nullable android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.Descramblers);
+    method public void setDiseqcMessages(@Nullable android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.DiseqcMessages);
+    method public void setDvrs(@Nullable android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.Dvrs);
+    method public void setFilters(@Nullable android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.Filters);
+    method public void setFrontends(@Nullable android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.Frontends);
+    method public void setLnbs(@Nullable android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.Lnbs);
+    method public void setTimeFilters(@Nullable android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.TimeFilters);
+  }
+
+  public static class HardwareConfiguration.Descramblers {
+    ctor public HardwareConfiguration.Descramblers();
+    method @Nullable public java.util.List<android.media.tuner.testing.configuration.V1_0.Descrambler> getDescrambler();
+  }
+
+  public static class HardwareConfiguration.DiseqcMessages {
+    ctor public HardwareConfiguration.DiseqcMessages();
+    method @Nullable public java.util.List<android.media.tuner.testing.configuration.V1_0.DiseqcMessage> getDiseqcMessage();
+  }
+
+  public static class HardwareConfiguration.Dvrs {
+    ctor public HardwareConfiguration.Dvrs();
+    method @Nullable public java.util.List<android.media.tuner.testing.configuration.V1_0.Dvr> getDvr();
+  }
+
+  public static class HardwareConfiguration.Filters {
+    ctor public HardwareConfiguration.Filters();
+    method @Nullable public java.util.List<android.media.tuner.testing.configuration.V1_0.Filter> getFilter();
+  }
+
+  public static class HardwareConfiguration.Frontends {
+    ctor public HardwareConfiguration.Frontends();
+    method @Nullable public java.util.List<android.media.tuner.testing.configuration.V1_0.Frontend> getFrontend();
+  }
+
+  public static class HardwareConfiguration.Lnbs {
+    ctor public HardwareConfiguration.Lnbs();
+    method @Nullable public java.util.List<android.media.tuner.testing.configuration.V1_0.Lnb> getLnb();
+  }
+
+  public static class HardwareConfiguration.TimeFilters {
+    ctor public HardwareConfiguration.TimeFilters();
+    method @Nullable public java.util.List<android.media.tuner.testing.configuration.V1_0.TimeFilter> getTimeFilter();
+  }
+
+  public class Lnb {
+    ctor public Lnb();
+    method @Nullable public String getId();
+    method @Nullable public String getName();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.LnbPositionEnum getPosition();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.LnbToneEnum getTone();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.LnbVoltageEnum getVoltage();
+    method public void setId(@Nullable String);
+    method public void setName(@Nullable String);
+    method public void setPosition(@Nullable android.media.tuner.testing.configuration.V1_0.LnbPositionEnum);
+    method public void setTone(@Nullable android.media.tuner.testing.configuration.V1_0.LnbToneEnum);
+    method public void setVoltage(@Nullable android.media.tuner.testing.configuration.V1_0.LnbVoltageEnum);
+  }
+
+  public enum LnbPositionEnum {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.LnbPositionEnum POSITION_A;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.LnbPositionEnum POSITION_B;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.LnbPositionEnum UNDEFINED;
+  }
+
+  public enum LnbToneEnum {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.LnbToneEnum CONTINUOUS;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.LnbToneEnum NONE;
+  }
+
+  public enum LnbVoltageEnum {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.LnbVoltageEnum NONE;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.LnbVoltageEnum VOLTAGE_11V;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.LnbVoltageEnum VOLTAGE_12V;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.LnbVoltageEnum VOLTAGE_13V;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.LnbVoltageEnum VOLTAGE_14V;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.LnbVoltageEnum VOLTAGE_15V;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.LnbVoltageEnum VOLTAGE_18V;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.LnbVoltageEnum VOLTAGE_19V;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.LnbVoltageEnum VOLTAGE_5V;
+  }
+
+  public class RecordFilterSettings {
+    ctor public RecordFilterSettings();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.ScIndexTypeEnum getScIndexType();
+    method @Nullable public java.math.BigInteger getTsIndexMask();
+    method public void setScIndexType(@Nullable android.media.tuner.testing.configuration.V1_0.ScIndexTypeEnum);
+    method public void setTsIndexMask(@Nullable java.math.BigInteger);
+  }
+
+  public enum ScIndexTypeEnum {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.ScIndexTypeEnum NONE;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.ScIndexTypeEnum SC;
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.ScIndexTypeEnum SC_HEVC;
+  }
+
+  public class SectionFilterSettings {
+    ctor public SectionFilterSettings();
+    method @Nullable public boolean getIsCheckCrc();
+    method @Nullable public boolean getIsRaw();
+    method @Nullable public boolean getIsRepeat();
+    method public void setIsCheckCrc(@Nullable boolean);
+    method public void setIsRaw(@Nullable boolean);
+    method public void setIsRepeat(@Nullable boolean);
+  }
+
+  public class TimeFilter {
+    ctor public TimeFilter();
+    method @Nullable public String getId();
+    method @Nullable public java.math.BigInteger getTimeStamp();
+    method public void setId(@Nullable String);
+    method public void setTimeStamp(@Nullable java.math.BigInteger);
+  }
+
+  public class TunerConfiguration {
+    ctor public TunerConfiguration();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration getDataFlowConfiguration();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.HardwareConfiguration getHardwareConfiguration();
+    method @Nullable public android.media.tuner.testing.configuration.V1_0.Version getVersion();
+    method public void setDataFlowConfiguration(@Nullable android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration);
+    method public void setHardwareConfiguration(@Nullable android.media.tuner.testing.configuration.V1_0.HardwareConfiguration);
+    method public void setVersion(@Nullable android.media.tuner.testing.configuration.V1_0.Version);
+  }
+
+  public enum Version {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.media.tuner.testing.configuration.V1_0.Version _1_0;
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method @Nullable public static android.media.tuner.testing.configuration.V1_0.TunerConfiguration read(@NonNull java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @Nullable public static String readText(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/tv/tuner/config/api/last_current.txt b/tv/tuner/config/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tv/tuner/config/api/last_current.txt
diff --git a/tv/tuner/config/api/last_removed.txt b/tv/tuner/config/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tv/tuner/config/api/last_removed.txt
diff --git a/tv/tuner/config/api/removed.txt b/tv/tuner/config/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/tv/tuner/config/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/tv/tuner/config/sample_tuner_vts_config.xml b/tv/tuner/config/sample_tuner_vts_config.xml
new file mode 100644
index 0000000..570171e
--- /dev/null
+++ b/tv/tuner/config/sample_tuner_vts_config.xml
@@ -0,0 +1,224 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- 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.
+-->
+
+<!-- The Sample Tuner Testing Configuration.
+    Name the customized xml with "tuner_vts_config.xml" and push into the device
+    "/vendor/etc" path. Please use "tuner_testing_dynamic_configuration.xsd" to verify the xml.
+    The version section contains a “version” tag in the form “major.minor” e.g version=”1.0”
+    This shows the tuner dynamic configuration version. -->
+<TunerConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <!-- Hardware Configuration section contains the configurations of all the hardwares
+        that would be used in the tests. In the "dataFlowConfiguration" section, each data flow
+        under test has its required/optional hardwares. The ids configured in the
+        "dataFlowConfiguration" would be used to connect the hardware to each data flow test. -->
+    <hardwareConfiguration>
+        <!-- Frontends section:
+            This section contains configurations of all the frontends that would be used
+                in the tests.
+                - This section is optional and can be skipped to use the default fe settings.
+                - The default settings can be found in the sample_tuner_vts_configurations.xml.
+                - The users can also override the default frontend settings using id="FE_DEFAULT".
+                - The users can configure 1 or more frontend elements in the frontends sections.
+
+            Each frontend element contain the following attributes:
+                "id": unique id of the frontend that could be used to connect to the test the
+                    "dataFlowConfiguration"
+                "type": the frontend type. The enums are defined in the xsd.
+                "isSoftwareFrontend": if the test environment is using hardware or software
+                    frontend. If using software, a ts input file path needs to be configured.
+                "softwareFeInputPath": used as the source of the software frontend.
+                "connectToCicamId": if the device supports frontend connecting to cicam, the target
+                    cicam id needs to be configured here. Supported in Tuner 1.1 or higher.
+                "frequency": the frequency used to configure tune and scan.
+                "endFrequency": the end frequency of scan. Supported in Tuner 1.1 or higher.
+
+            Each frontend element also contains one and only one type-related "frontendSettings".
+                - The settings type should match the frontend "type" attribute.
+                - For example, when frontend type="DVBT", dvbtFrontendSettings can be configured.
+                - This is optional and skipping the settings would pass a setting with frequency
+                    config only to the hal.
+        -->
+        <frontends>
+            <frontend id="FE_DEFAULT" type="DVBT" isSoftwareFrontend="true"
+                      connectToCicamId="0" frequency="578000" endFrequency="800000">
+                <dvbtFrontendSettings bandwidth="8" transmissionMode="1" isHighPriority="1"/>
+            </frontend>
+            <frontend id="FE_DVBS_0" type="DVBS" isSoftwareFrontend="true"
+                      connectToCicamId="0" frequency="578000" endFrequency="800000">
+            </frontend>
+        </frontends>
+        <!-- Filter section:
+            This section contains configurations of all the filters that would be used in the tests.
+                - This section is optional and can be skipped to use the default filter settings.
+                - The default settings can be found in the sample_tuner_vts_configurations.xml.
+                - The users can also override the default filter settings using
+                - id="FILTER_AUDIO_DEFAULT" or "FILTER_VIDEO_DEFAULT".
+                - The users can configure 1 or more filter elements in the filters sections.
+
+            Each filter element contain the following attributes:
+                "id": unique id of the filter that could be used to connect to the test the
+                    "dataFlowConfiguration"
+                "mainType": the main filter type. The enums are defined in the xsd.
+                "subType": the sub filter type. The enums are defined in the xsd.
+                "bufferSize": the buffer size of the filter in hex.
+                "pid": the pid that would be used to configure the filter.
+                "useFMQ": if the filter uses FMQ.
+
+            Each filter element also contains at most one type-related "filterSettings".
+                - The settings type should match the filter "subType" attribute.
+                - For example, when filter subType is audio or video, the avFilterSettings can be
+                    configured.
+                - This is optional and skipping the settings would pass a setting with tpid config
+                    only to the hal.
+        -->
+        <filters>
+            <filter id="FILTER_AUDIO_DEFAULT" mainType="TS" subType="AUDIO"
+                    bufferSize="16777216" pid="257" useFMQ="false">
+                <avFilterSettings isPassthrough="false"/>
+            </filter>
+            <filter id="FILTER_VIDEO_DEFAULT" mainType="TS" subType="VIDEO"
+                    bufferSize="16777216" pid="256" useFMQ="false">
+                <avFilterSettings isPassthrough="false"/>
+            </filter>
+            <filter id="FILTER_TS_RECORD_0" mainType="TS" subType="RECORD"
+                    bufferSize="16777216" pid="257" useFMQ="false">
+                <recordFilterSettings tsIndexMask="1" scIndexType="NONE"/>
+            </filter>
+            <filter id="FILTER_TS_SECTION_0" mainType="TS" subType="SECTION"
+                    bufferSize="16777216" pid="257" useFMQ="true">
+                <sectionFilterSettings isCheckCrc="false" isRepeat="false" isRaw="false"/>
+            </filter>
+            <filter id="FILTER_TS_PCR_0" mainType="TS" subType="PCR"
+                    bufferSize="16777216" pid="256" useFMQ="false">
+            </filter>
+        </filters>
+        <!-- Dvr section:
+            This section contains configurations of all the dvrs that would be used in the tests.
+                - This section is optional and can be skipped if DVR is not supported.
+                - The users can configure 1 or more dvr elements in the dvrs sections.
+
+            Each dvr element contain the following attributes:
+                "id": unique id of the dvr that could be used to connect to the test the
+                    "dataFlowConfiguration"
+                "type": the dvr type.
+                "bufferSize": the dvr buffer size.
+                "statusMask": register callbacks of specific status.
+                "lowThreshold": the dvr status low threshold.
+                "highThreshold": the dvr status high threshold.
+                "dataFormat": the dvr data format.
+                "packetSize": the dvr packet size.
+                "inputFilePath": the dvr playback input file path. Only required in playback dvr.
+        -->
+        <dvrs>
+            <dvr id="DVR_PLAYBACK_0" type="PLAYBACK" bufferSize="4194304"
+                 statusMask="15" lowThreshold="4096" highThreshold="32767"
+                 dataFormat="TS" packetSize="188" inputFilePath="/data/local/tmp/segment000000.ts"/>
+            <dvr id="DVR_RECORD_0" type="RECORD" bufferSize="4194304"
+                 statusMask="15" lowThreshold="4096" highThreshold="32767"
+                 dataFormat="TS" packetSize="188"/>
+            <dvr id="DVR_PLAYBACK_1" type="PLAYBACK" bufferSize="4194304"
+                 statusMask="15" lowThreshold="4096" highThreshold="32767"
+                 dataFormat="ES" packetSize="188" inputFilePath="/data/local/tmp/test.es"/>
+        </dvrs>
+        <!-- Lnb section:
+            This section contains configurations of all the lnbs that would be used in the tests.
+                - This section is optional and can be skipped if LNB is not supported.
+                - The users can configure 1 or more lnb elements in the lnbs sections.
+
+            Each lnb element contain the following attributes:
+                "id": unique id of the lnb that could be used to connect to the test the
+                    "dataFlowConfiguration"
+                "name": the external lnb device name.
+                "voltage": the voltage used to config the lnb.
+                "tone": the voltage used to config the lnb.
+                "position": the voltage used to config the lnb.
+        -->
+        <diseqcMessages>
+            <diseqcMessage msgName="DISEQC_POWER_ON" msgBody="14 0 0 0 0 3"/>
+        </diseqcMessages>
+        <lnbs>
+            <lnb id="LNB_0" voltage="VOLTAGE_12V" tone="NONE" position="UNDEFINED"/>
+            <lnb id="LNB_1" name="default_lnb_external" voltage="VOLTAGE_5V"
+                            tone="NONE" position="UNDEFINED"/>
+        </lnbs>
+        <!-- TimeFilter section:
+            This section contains configurations of all the time filters that would be used in
+            the tests.
+                - This section is optional and can be skipped if Time Filter is not supported.
+                - The users can configure 1 or more timeFilter elements in the timeFilters sections.
+
+            Each timeFilter element contain the following attributes:
+                "id": unique id of the time filter that could be used to connect to the test the
+                    "dataFlowConfiguration"
+                "timeStamp": the time stamp used to config the time filter.
+        -->
+        <timeFilters>
+            <timeFilter id="TIME_FILTER_0" timeStamp="1"/>
+        </timeFilters>
+        <!-- Descrambler section:
+            This section contains configurations of all the descramblers that would be used in
+            the tests.
+                - This section is optional and can be skipped if Descrambler is not supported.
+                - The users can configure 1 or more descrambler elements in the descramblers sections.
+
+            Each Descrambler element contain the following attributes:
+                "id": unique id of the descrambler that could be used to connect to the test the
+                    "dataFlowConfiguration"
+                "casSystemId": the cas system id to connect to the descrambler.
+                "provisionStr": the provision string to use with the cas plugin.
+                "sesstionPrivatData": the session private data used to open the cas session.
+        -->
+        <descramblers>
+            <descrambler id="DESCRAMBLER_0" casSystemId="63192"/>
+        </descramblers>
+    </hardwareConfiguration>
+
+    <!-- Data flow configuration section connects each data flow under test to the ids of the
+        hardwares that would be used during the tests. -->
+    <dataFlowConfiguration>
+        <clearLiveBroadcast frontendConnection="FE_DEFAULT"
+                            audioFilterConnection="FILTER_AUDIO_DEFAULT"
+                            videoFilterConnection="FILTER_VIDEO_DEFAULT"
+                            pcrFilterConnection="FILTER_TS_PCR_0"
+                            sectionFilterConnection="FILTER_TS_SECTION_0"
+                            dvrSoftwareFeConnection="DVR_PLAYBACK_0"/>
+        <scan frontendConnection="FE_DEFAULT"/>
+        <descrambling frontendConnection="FE_DEFAULT"
+                      descramblerConnection="DESCRAMBLER_0"
+                      audioFilterConnection="FILTER_AUDIO_DEFAULT"
+                      videoFilterConnection="FILTER_VIDEO_DEFAULT"
+                      dvrSoftwareFeConnection="DVR_PLAYBACK_0"/>
+        <dvrPlayback dvrConnection="DVR_PLAYBACK_0"
+                     audioFilterConnection="FILTER_AUDIO_DEFAULT"
+                     videoFilterConnection="FILTER_VIDEO_DEFAULT"
+                     sectionFilterConnection="FILTER_TS_SECTION_0"/>
+        <dvrRecord frontendConnection="FE_DEFAULT"
+                   recordFilterConnection="FILTER_TS_RECORD_0"
+                   dvrRecordConnection="DVR_RECORD_0"
+                   dvrSoftwareFeConnection="DVR_PLAYBACK_0"/>
+        <lnbLive frontendConnection="FE_DVBS_0"
+                 audioFilterConnection="FILTER_AUDIO_DEFAULT"
+                 videoFilterConnection="FILTER_VIDEO_DEFAULT"
+                 lnbConnection="LNB_1"
+                 diseqcMsgSender="DISEQC_POWER_ON"/>
+        <lnbRecord frontendConnection="FE_DVBS_0"
+                   recordFilterConnection="FILTER_TS_RECORD_0"
+                   dvrRecordConnection="DVR_RECORD_0"
+                   lnbConnection="LNB_0"
+                   diseqcMsgSender="DISEQC_POWER_ON"/>
+        <timeFilter timeFilterConnection="TIME_FILTER_0"/>
+    </dataFlowConfiguration>
+</TunerConfiguration>
diff --git a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
new file mode 100644
index 0000000..3fe93ff
--- /dev/null
+++ b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd
@@ -0,0 +1,644 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<xs:schema version="2.0"
+           elementFormDefault="qualified"
+           attributeFormDefault="unqualified"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    <!-- List the dynamic config versions supported by tuner testing. -->
+    <xs:simpleType name="version">
+        <xs:restriction base="xs:decimal">
+            <xs:enumeration value="1.0"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <!-- FRONTEND SESSION -->
+    <xs:simpleType name="frontendId">
+        <!-- Frontend id must be either FE_DEFAULT or FE_TYPE_NUM
+            <frontend id="FE_DVBS_0"/>
+        -->
+        <xs:restriction base="xs:string">
+            <xs:pattern value="FE_DEFAULT|FE_[A-Z]+_[0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="frontendTypeEnum">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="UNDEFINED" />
+            <xs:enumeration value="ANALOG" />
+            <xs:enumeration value="ATSC" />
+            <xs:enumeration value="ATSC3"/>
+            <xs:enumeration value="DVBC"/>
+            <xs:enumeration value="DVBS"/>
+            <xs:enumeration value="DVBT"/>
+            <xs:enumeration value="ISDBS"/>
+            <xs:enumeration value="ISDBS3"/>
+            <xs:enumeration value="ISDBT"/>
+            <xs:enumeration value="DTMB"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="dvbtFrontendSettings">
+        <xs:attribute name="bandwidth" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="transmissionMode" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="isHighPriority" type="xs:nonNegativeInteger" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="dvbsFrontendSettings">
+        <xs:attribute name="inputStreamId" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="symbolRate" type="xs:nonNegativeInteger" use="required"/>
+    </xs:complexType>
+
+    <xs:complexType name="frontend">
+        <xs:annotation>
+            <xs:documentation>
+                Each frontend element contain the following attributes:
+                    "id": unique id of the frontend that could be used to connect to the test the
+                        "dataFlowConfiguration"
+                    "type": the frontend type. The enums are defined in the xsd.
+                    "isSoftwareFrontend": if the test environment is using hardware or software
+                        frontend. If using software, a ts input file path needs to be configured.
+                    "softwareFeInputPath": used as the source of the software frontend.
+                    "connectToCicamId": if the device supports frontend connecting to cicam, the
+                        target cicam id needs to be configured here. Supported in Tuner 1.1 or
+                        higher.
+                    "frequency": the frequency used to configure tune and scan.
+                    "endFrequency": the end frequency of scan. Supported in Tuner 1.1 or higher.
+
+                Each frontend element also contains at most one type-related "frontendSettings".
+                    - The settings type should match the frontend "type" attribute.
+                    - For example, when frontend type="DVBT", dvbtFrontendSettings can be
+                        configured.
+                    - This is optional and skipping the settings would pass a setting with frequency
+                        config only to the hal.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:choice minOccurs="0" maxOccurs="1">
+            <!-- TODO: b/182519645 finish all the frontend settings structures. -->
+            <!--xs:element name="analog" type="analogSettings"/>
+            <xs:element name="atsc" type="atscSettings"/>
+            <xs:element name="atsc3" type="atsc3Settings"/>
+            <xs:element name="dvbc" type="dvbcSettings"/-->
+            <xs:element name="dvbsFrontendSettings" type="dvbsFrontendSettings"/>
+            <xs:element name="dvbtFrontendSettings" type="dvbtFrontendSettings"/>
+            <!--xs:element name="isdbs" type="isdbsSettings"/>
+            <xs:element name="isdbs3" type="isdbs3Settings"/>
+            <xs:element name="isdbt" type="isdbtSettings"/>
+            <xs:element name="dtmb" type="dtmbSettings"/-->
+        </xs:choice>
+        <xs:attribute name="id" type="frontendId" use="required"/>
+        <xs:attribute name="type" type="frontendTypeEnum" use="required"/>
+        <!-- A dvr connection is required in the data flow config section when
+            "isSoftwareFrontend" is true. -->
+        <xs:attribute name="isSoftwareFrontend" type="xs:boolean" use="required"/>
+        <xs:attribute name="frequency" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="connectToCicamId" type="xs:nonNegativeInteger" use="optional"/>
+        <xs:attribute name="endFrequency" type="xs:nonNegativeInteger" use="optional"/>
+    </xs:complexType>
+
+    <!-- FILTER SESSION -->
+    <xs:simpleType name="filterId">
+        <!-- Filter id must be either FILTER_AUDIO_DEFAULT or FILTER_VIDEO_DEFAULT
+             or FILTER_MAINTYPE_SUBTYPE_NUM
+            <filter id="FILTER_TS_AUDIO_0"/>
+        -->
+        <xs:restriction base="xs:string">
+            <xs:pattern value="FILTER_AUDIO_DEFAULT|FILTER_VIDEO_DEFAULT|FILTER_[A-Z]+_[A-Z]+_[0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- A list of filter ids that could be used in the data flow configurations to connect
+        filters under testing. -->
+    <xs:simpleType name="filterConnections">
+        <xs:list itemType="filterId" />
+    </xs:simpleType>
+    <!-- DemuxFilterRecordSettings::tsIndexMask -->
+    <xs:simpleType name="tsIndexMask">
+        <xs:restriction base="xs:integer">
+            <xs:minInclusive value="0"/>
+            <xs:maxInclusive value="8191"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- DemuxFilterRecordSettings::scIndexType -->
+    <xs:simpleType name="scIndexTypeEnum">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="NONE" />
+            <xs:enumeration value="SC" />
+            <xs:enumeration value="SC_HEVC"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="filterMainTypeEnum">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="TS" />
+            <xs:enumeration value="MMTP" />
+            <!-- TODO: b/182519645 Support IP/TLV/ALP filter config
+            <xs:enumeration value="IP"/>
+            <xs:enumeration value="TLV"/>
+            <xs:enumeration value="ALP"/-->
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="filterSubTypeEnum">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="UNDEFINED" />
+            <xs:enumeration value="SECTION" />
+            <xs:enumeration value="PES" />
+            <xs:enumeration value="TS"/>
+            <xs:enumeration value="AUDIO"/>
+            <xs:enumeration value="VIDEO"/>
+            <xs:enumeration value="PCR"/>
+            <xs:enumeration value="RECORD"/>
+            <xs:enumeration value="TEMI"/>
+            <xs:enumeration value="MMTP"/>
+            <xs:enumeration value="DOWNLOAD"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="avFilterSettings">
+        <xs:attribute name="isPassthrough" type="xs:boolean" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="sectionFilterSettings">
+        <xs:attribute name="isCheckCrc" type="xs:boolean" use="required"/>
+        <xs:attribute name="isRepeat" type="xs:boolean" use="required"/>
+        <xs:attribute name="isRaw" type="xs:boolean" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="recordFilterSettings">
+        <xs:attribute name="tsIndexMask" type="tsIndexMask" use="required"/>
+        <xs:attribute name="scIndexType" type="scIndexTypeEnum" use="required"/>
+    </xs:complexType>
+
+    <xs:complexType name="filter">
+        <xs:annotation>
+            <xs:documentation>
+                Each filter element contain the following attributes:
+                    "id": unique id of the filter that could be used to connect to the test the
+                        "dataFlowConfiguration"
+                    "mainType": the main filter type. The enums are defined in the xsd.
+                    "subType": the sub filter type. The enums are defined in the xsd.
+                    "bufferSize": the buffer size of the filter in hex.
+                    "pid": the pid that would be used to configure the filter.
+                    "useFMQ": if the filter uses FMQ.
+
+                Each filter element also contains at most one type-related "filterSettings".
+                    - The settings type should match the filter "subType" attribute.
+                    - For example, when filter subType is audio or video, the avFilterSettings
+                        can be configured.
+                    - This is optional and skipping the settings would pass a setting with tpid
+                        config only to the hal.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:choice minOccurs="0" maxOccurs="1">
+            <!-- TODO: b/182519645 finish all the filter settings structures. -->
+            <xs:element name="sectionFilterSettings" type="sectionFilterSettings"/>
+            <xs:element name="avFilterSettings" type="avFilterSettings"/>
+            <xs:element name="recordFilterSettings" type="recordFilterSettings"/>
+            <!--xs:element name="pes" type="pesFilterSettings"/>
+            <xs:element name="download" type="downloadFilterSettings"/-->
+        </xs:choice>
+        <xs:attribute name="id" type="filterId" use="required"/>
+        <xs:attribute name="mainType" type="filterMainTypeEnum" use="required"/>
+        <xs:attribute name="subType" type="filterSubTypeEnum" use="required"/>
+        <xs:attribute name="bufferSize" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="pid" type="xs:nonNegativeInteger" use="optional"/>
+        <xs:attribute name="useFMQ" type="xs:boolean" use="required"/>
+    </xs:complexType>
+
+    <!-- DVR SESSION -->
+    <xs:simpleType name="dvrId">
+        <!-- Dvr id must be DVR_TYPE_NUM. <dvr id="DVR_PLAYBACK_0"/> -->
+        <xs:restriction base="xs:string">
+            <xs:pattern value="DVR_RECORD_[0-9]+|DVR_PLAYBACK_[0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="dvrStatusMask">
+        <!-- Dvr status mask must masking the <dvrStatusEnum> -->
+        <xs:restriction base="xs:integer">
+            <xs:minInclusive value="0"/>
+            <xs:maxInclusive value="15"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="dvrStatusEnum">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="DATA_READY" />
+            <xs:enumeration value="LOW_WATER" />
+            <xs:enumeration value="HIGH_WATER" />
+            <xs:enumeration value="OVERFLOW" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="dvrTypeEnum">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="PLAYBACK" />
+            <xs:enumeration value="RECORD" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="dvrDataFormatEnum">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="TS" />
+            <xs:enumeration value="PES" />
+            <xs:enumeration value="ES" />
+            <xs:enumeration value="SHV_TLV" />
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="dvr">
+        <xs:annotation>
+            <xs:documentation>
+                Each dvr element contain the following attributes:
+                    "id": unique id of the dvr that could be used to connect to the test the
+                        "dataFlowConfiguration"
+                    "type": the dvr type.
+                    "bufferSize": the dvr buffer size.
+                    "statusMask": register callbacks of specific status.
+                    "lowThreshold": the dvr status low threshold.
+                    "highThreshold": the dvr status high threshold.
+                    "dataFormat": the dvr data format.
+                    "packetSize": the dvr packet size.
+                    "inputFilePath": the dvr playback input file path. Only required in playback
+                        dvr.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="id" type="dvrId" use="required"/>
+        <xs:attribute name="type" type="dvrTypeEnum" use="required"/>
+        <xs:attribute name="bufferSize" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="statusMask" type="dvrStatusMask" use="required"/>
+        <xs:attribute name="lowThreshold" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="highThreshold" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="dataFormat" type="dvrDataFormatEnum" use="required"/>
+        <xs:attribute name="packetSize" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="inputFilePath" type="xs:anyURI" use="optional"/>
+    </xs:complexType>
+
+    <!-- LNB SESSION -->
+    <xs:simpleType name="lnbId">
+        <!-- Lnb id must be LNB_NUM: <lnb id="LNB_10"/> -->
+        <xs:restriction base="xs:string">
+            <xs:pattern value="LNB_[0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="lnbVoltageEnum">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="NONE" />
+            <xs:enumeration value="VOLTAGE_5V" />
+            <xs:enumeration value="VOLTAGE_11V" />
+            <xs:enumeration value="VOLTAGE_12V"/>
+            <xs:enumeration value="VOLTAGE_13V"/>
+            <xs:enumeration value="VOLTAGE_14V"/>
+            <xs:enumeration value="VOLTAGE_15V"/>
+            <xs:enumeration value="VOLTAGE_18V"/>
+            <xs:enumeration value="VOLTAGE_19V"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="lnbToneEnum">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="NONE" />
+            <xs:enumeration value="CONTINUOUS" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="lnbPositionEnum">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="UNDEFINED" />
+            <xs:enumeration value="POSITION_A" />
+            <xs:enumeration value="POSITION_B" />
+        </xs:restriction>
+    </xs:simpleType>
+
+    <!-- Diseqc Messages that would be used to send to the lnb under test. -->
+    <xs:simpleType name="diseqcMsgName">
+        <xs:restriction base="xs:string">
+            <xs:pattern value="[A-Z_]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="diseqcMsgBody">
+        <xs:list itemType="xs:unsignedByte"/>
+    </xs:simpleType>
+    <xs:complexType name="diseqcMessage">
+        <xs:attribute name="msgName" type="diseqcMsgName"/>
+        <xs:attribute name="msgBody" type="diseqcMsgBody"/>
+    </xs:complexType>
+    <xs:simpleType name="diseqcMsgSender">
+        <xs:list itemType="diseqcMsgName"/>
+    </xs:simpleType>
+
+    <xs:complexType name="lnb">
+        <xs:annotation>
+            <xs:documentation>
+                Each lnb element contain the following attributes:
+                    "id": unique id of the lnb that could be used to connect to the test the
+                        "dataFlowConfiguration"
+                    "name": the external lnb device name.
+                    "voltage": the voltage used to config the lnb.
+                    "tone": the voltage used to config the lnb.
+                    "position": the voltage used to config the lnb.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="id" type="lnbId" use="required"/>
+        <!-- Only required on external lnb with no device id. -->
+        <xs:attribute name="name" type="xs:string" use="optional"/>
+        <xs:attribute name="voltage" type="lnbVoltageEnum" use="required"/>
+        <xs:attribute name="tone" type="lnbToneEnum" use="required"/>
+        <xs:attribute name="position" type="lnbPositionEnum" use="required"/>
+    </xs:complexType>
+
+    <!-- TIME FILTER SESSION -->
+    <xs:simpleType name="timeFilterId">
+        <!-- Time Filter id must be TIME_FILTER_NUM: <timeFilter id="TIME_FILTER_1"/> -->
+        <xs:restriction base="xs:string">
+            <xs:pattern value="TIME_FILTER_[0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="timeFilter">
+        <xs:annotation>
+            <xs:documentation>
+                Each timeFilter element contain the following attributes:
+                    "id": unique id of the time filter that could be used to connect to the test the
+                        "dataFlowConfiguration"
+                    "timeStamp": the time stamp used to config the time filter.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="id" type="timeFilterId" use="required"/>
+        <xs:attribute name="timeStamp" type="xs:nonNegativeInteger" use="required"/>
+    </xs:complexType>
+
+    <!-- DESCRAMBLER SESSION -->
+    <xs:simpleType name="descramblerId">
+        <!-- Descrambler id must be DESCRAMBLER_NUM: <descrambler id="DESCRAMBLER_2"/> -->
+        <xs:restriction base="xs:string">
+            <xs:pattern value="DESCRAMBLER_[0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="sessionPrivateData">
+        <xs:list itemType="xs:unsignedByte"/>
+    </xs:simpleType>
+
+    <xs:complexType name="descrambler">
+        <xs:annotation>
+            <xs:documentation>
+                Each descrambler element contain the following attributes:
+                    "id": unique id of the descrambler that could be used to connect to the test the
+                        "dataFlowConfiguration"
+                    "casSystemId": the cas system id to connect to the descrambler.
+                    "provisionStr": the provision string to use with the cas plugin.
+                    "sesstionPrivatData": the session private data used to open the cas session.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:attribute name="id" type="descramblerId" use="required"/>
+        <xs:attribute name="casSystemId" type="xs:nonNegativeInteger" use="required"/>
+        <xs:attribute name="provisionStr" type="xs:string" use="required"/>
+        <xs:attribute name="sesstionPrivatData" type="sessionPrivateData" use="optional"/>
+    </xs:complexType>
+
+    <!-- HARDWARE CONFIGURATION SESSION -->
+    <xs:complexType name="hardwareConfiguration">
+        <xs:sequence>
+            <xs:element name="frontends" minOccurs="0" maxOccurs="1">
+                <xs:complexType>
+                    <xs:annotation>
+                        <xs:documentation xml:lang="en">
+                            This section contains configurations of all the frontends that would be
+                                used in the tests.
+                                - This section is optional and can be skipped to use the default
+                                    fe settings.
+                                - The default settings can be found in the
+                                    sample_tuner_vts_configurations.xml.
+                                - The users can also override the default frontend settings using
+                                    id="FE_DEFAULT".
+                                - The users can configure 1 or more frontend elements in the
+                                    frontends sections.
+                        </xs:documentation>
+                    </xs:annotation>
+                    <xs:sequence>
+                        <xs:element name="frontend" type="frontend" minOccurs="1" maxOccurs="unbounded"/>
+                    </xs:sequence>
+                </xs:complexType>
+            </xs:element>
+            <xs:element name="filters" minOccurs="0" maxOccurs="1">
+                <xs:complexType>
+                    <xs:annotation>
+                        <xs:documentation xml:lang="en">
+                            This section contains configurations of all the filters that would be
+                                used in the tests.
+                                - This section is optional and can be skipped to use the default
+                                    filter settings.
+                                - The default settings can be found in the
+                                    sample_tuner_vts_configurations.xml.
+                                - The users can also override the default filter settings using
+                                - id="FILTER_AUDIO_DEFAULT" or "FILTER_VIDEO_DEFAULT".
+                                - The users can configure 1 or more filter elements in the filters
+                                    sections.
+                        </xs:documentation>
+                    </xs:annotation>
+                    <xs:sequence>
+                        <xs:element name="filter" type="filter" minOccurs="1" maxOccurs="unbounded"/>
+                    </xs:sequence>
+                </xs:complexType>
+            </xs:element>
+            <xs:element name="dvrs" minOccurs="0" maxOccurs="1">
+                <xs:complexType>
+                    <xs:annotation>
+                        <xs:documentation xml:lang="en">
+                            This section contains configurations of all the dvrs that would be used
+                                in the tests.
+                                - This section is optional and can be skipped if the device does
+                                    not support dvr.
+                                - The users can configure 1 or more dvr elements in the dvrs
+                                   sections.
+                        </xs:documentation>
+                    </xs:annotation>
+                    <xs:sequence>
+                        <xs:element name="dvr" type="dvr" minOccurs="1" maxOccurs="unbounded"/>
+                    </xs:sequence>
+                </xs:complexType>
+            </xs:element>
+            <xs:element name="diseqcMessages" minOccurs="0" maxOccurs="1">
+                <xs:complexType>
+                    <xs:annotation>
+                        <xs:documentation xml:lang="en">
+                            This section contains configurations of all the diseqc messages that
+                            would be used in the lnb tests.
+                                - This section is optional and can be skipped if lnb is not suppoted
+                                - The users can configure 1 or more message elements in the
+                                    diseqcMessages sections.
+                        </xs:documentation>
+                    </xs:annotation>
+                    <xs:sequence>
+                        <xs:element name="diseqcMessage" type="diseqcMessage" minOccurs="1" maxOccurs="unbounded"/>
+                    </xs:sequence>
+                </xs:complexType>
+            </xs:element>
+            <xs:element name="lnbs" minOccurs="0" maxOccurs="1">
+                <xs:complexType>
+                    <xs:annotation>
+                        <xs:documentation xml:lang="en">
+                            This section contains configurations of all the lnbs that would be used
+                                in the tests.
+                                - This section is optional and can be skipped if lnb is not suppoted
+                                - The users can configure 1 or more lnb elements in the lnbs
+                                    sections.
+                        </xs:documentation>
+                    </xs:annotation>
+                    <xs:sequence>
+                        <xs:element name="lnb" type="lnb" minOccurs="1" maxOccurs="unbounded"/>
+                    </xs:sequence>
+                </xs:complexType>
+            </xs:element>
+            <xs:element name="timeFilters" minOccurs="0" maxOccurs="1">
+                <xs:complexType>
+                    <xs:annotation>
+                        <xs:documentation xml:lang="en">
+                            This section contains configurations of all the time filters that would
+                                be used in the tests.
+                                - This section is optional and can be skipped if time filter is
+                                    not supported.
+                                - The users can configure 1 or more time filter elements in the
+                                    time filters sections.
+                        </xs:documentation>
+                    </xs:annotation>
+                    <xs:sequence>
+                        <xs:element name="timeFilter" type="timeFilter" minOccurs="1" maxOccurs="unbounded"/>
+                    </xs:sequence>
+                </xs:complexType>
+            </xs:element>
+            <xs:element name="descramblers" minOccurs="0" maxOccurs="1">
+                <xs:complexType>
+                    <xs:annotation>
+                        <xs:documentation xml:lang="en">
+                            This section contains configurations of all the descramblers that would
+                                be used in the tests.
+                                - This section is optional and can be skipped if descrambling is not
+                                    supported.
+                                - The users can configure 1 or more descrambler elements in the
+                                    descramblers sections.
+                        </xs:documentation>
+                    </xs:annotation>
+                    <xs:sequence>
+                        <xs:element name="descrambler" type="descrambler" minOccurs="1" maxOccurs="unbounded"/>
+                    </xs:sequence>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <!-- DATA FLOW CONFIGURATION SESSION -->
+    <xs:complexType name="dataFlowConfiguration">
+        <xs:sequence>
+            <xs:element name="clearLiveBroadcast" minOccurs="1" maxOccurs="1">
+                <xs:complexType>
+                    <xs:attribute name="frontendConnection" type="frontendId" use="required"/>
+                    <xs:attribute name="audioFilterConnection" type="filterId" use="required"/>
+                    <xs:attribute name="videoFilterConnection" type="filterId" use="required"/>
+                    <xs:attribute name="pcrFilterConnection" type="filterId" use="optional"/>
+                    <xs:attribute name="sectionFilterConnection" type="filterId" use="optional"/>
+                    <!-- TODO: b/182519645 allow the users to insert extra filters -->
+                    <!-- DVR is only required when the frontend is using the software input -->
+                    <xs:attribute name="dvrSoftwareFeConnection" type="dvrId" use="optional"/>
+                </xs:complexType>
+            </xs:element>
+            <xs:element name="scan" minOccurs="1" maxOccurs="1">
+                <xs:complexType>
+                    <xs:attribute name="frontendConnection" type="frontendId" use="required"/>
+                </xs:complexType>
+            </xs:element>
+            <xs:element name="descrambling" minOccurs="0" maxOccurs="1">
+                <xs:complexType>
+                    <xs:attribute name="frontendConnection" type="frontendId" use="required"/>
+                    <xs:attribute name="descramblerConnection" type="descramblerId" use="required"/>
+                    <xs:attribute name="audioFilterConnection" type="filterId" use="required"/>
+                    <xs:attribute name="videoFilterConnection" type="filterId" use="required"/>
+                    <!-- TODO: b/182519645 allow the users to insert extra filters -->
+                    <!-- DVR is only required when the frontend is using the software input -->
+                    <xs:attribute name="dvrSoftwareFeConnection" type="dvrId" use="optional"/>
+                </xs:complexType>
+            </xs:element>
+            <xs:element name="dvrPlayback" minOccurs="0" maxOccurs="1">
+                <xs:complexType>
+                    <xs:attribute name="dvrConnection" type="dvrId" use="required"/>
+                    <xs:attribute name="audioFilterConnection" type="filterId" use="required"/>
+                    <xs:attribute name="videoFilterConnection" type="filterId" use="required"/>
+                    <xs:attribute name="sectionFilterConnection" type="filterId" use="optional"/>
+                    <!-- TODO: b/182519645 allow the users to insert extra filters -->
+                </xs:complexType>
+            </xs:element>
+            <xs:element name="dvrRecord" minOccurs="0" maxOccurs="1">
+                <xs:complexType>
+                    <xs:attribute name="frontendConnection" type="frontendId" use="required"/>
+                    <xs:attribute name="dvrRecordConnection" type="dvrId" use="required"/>
+                    <!-- DVR is only required when the frontend is using the software input -->
+                    <xs:attribute name="dvrSoftwareFeConnection" type="dvrId" use="optional"/>
+                    <xs:attribute name="recordFilterConnection" type="filterId" use="required"/>
+                </xs:complexType>
+            </xs:element>
+            <xs:element name="lnbLive" minOccurs="0" maxOccurs="1">
+                <xs:complexType>
+                    <xs:attribute name="frontendConnection" type="frontendId" use="required"/>
+                    <xs:attribute name="audioFilterConnection" type="filterId" use="required"/>
+                    <xs:attribute name="videoFilterConnection" type="filterId" use="required"/>
+                    <xs:attribute name="lnbConnection" type="lnbId" use="required"/>
+                    <xs:attribute name="diseqcMsgSender" type="diseqcMsgSender" use="optional"/>
+                    <!-- TODO: b/182519645 allow the users to insert extra filters -->
+                </xs:complexType>
+            </xs:element>
+            <xs:element name="lnbRecord" minOccurs="0" maxOccurs="1">
+                <xs:complexType>
+                    <xs:attribute name="frontendConnection" type="frontendId" use="required"/>
+                    <xs:attribute name="recordFilterConnection" type="filterId" use="required"/>
+                    <xs:attribute name="dvrRecordConnection" type="dvrId" use="required"/>
+                    <xs:attribute name="lnbConnection" type="lnbId" use="required"/>
+                    <xs:attribute name="diseqcMsgSender" type="diseqcMsgSender" use="optional"/>
+                </xs:complexType>
+            </xs:element>
+            <xs:element name="timeFilter" minOccurs="0" maxOccurs="1">
+                <xs:complexType>
+                    <xs:attribute name="timeFilterConnection" type="timeFilterId" use="required"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <!-- Full Tuner Configuration. This is the root element of the configuration xml. -->
+    <xs:element name="TunerConfiguration">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="hardwareConfiguration" type="hardwareConfiguration" minOccurs="1" maxOccurs="1"/>
+                <xs:element name="dataFlowConfiguration" type="dataFlowConfiguration" minOccurs="1" maxOccurs="1"/>
+            </xs:sequence>
+            <xs:attribute name="version" type="version"/>
+        </xs:complexType>
+        <xs:key name="frontendIdUniqueness">
+            <xs:selector xpath="hardwareConfiguration/frontends/frontend"/>
+            <xs:field xpath="@id"/>
+        </xs:key>
+        <xs:key name="filterIdUniqueness">
+            <xs:selector xpath="hardwareConfiguration/filters/filter"/>
+            <xs:field xpath="@id"/>
+        </xs:key>
+        <xs:key name="dvrIdUniqueness">
+            <xs:selector xpath="hardwareConfiguration/dvrs/dvr"/>
+            <xs:field xpath="@id"/>
+        </xs:key>
+        <xs:key name="lnbIdUniqueness">
+            <xs:selector xpath="hardwareConfiguration/lnbs/lnb"/>
+            <xs:field xpath="@id"/>
+        </xs:key>
+        <xs:key name="timeFilterIdUniqueness">
+            <xs:selector xpath="hardwareConfiguration/timeFilters/timeFilter"/>
+            <xs:field xpath="@id"/>
+        </xs:key>
+        <xs:key name="descramblerIdUniqueness">
+            <xs:selector xpath="hardwareConfiguration/descramblers/descrambler"/>
+            <xs:field xpath="@id"/>
+        </xs:key>
+    </xs:element>
+</xs:schema>
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/ActivePwle.aidl
similarity index 78%
copy from biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
copy to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/ActivePwle.aidl
index 4db47c9..de3ad3c 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/ActivePwle.aidl
@@ -31,21 +31,12 @@
 // 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.biometrics.face;
-@Backing(type="byte") @VintfStability
-enum SessionState {
-  IDLING = 0,
-  CLOSED = 1,
-  GENERATING_CHALLENGE = 2,
-  REVOKING_CHALLENGE = 3,
-  ENROLLING = 4,
-  AUTHENTICATING = 5,
-  DETECTING_INTERACTION = 6,
-  ENUMERATING_ENROLLMENTS = 7,
-  REMOVING_ENROLLMENTS = 8,
-  GETTING_FEATURES = 9,
-  SETTING_FEATURE = 10,
-  GETTING_AUTHENTICATOR_ID = 11,
-  INVALIDATING_AUTHENTICATOR_ID = 12,
-  RESETTING_LOCKOUT = 13,
+package android.hardware.vibrator;
+@VintfStability
+parcelable ActivePwle {
+  float startAmplitude;
+  float startFrequency;
+  float endAmplitude;
+  float endFrequency;
+  int duration;
 }
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Braking.aidl
similarity index 78%
copy from biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
copy to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Braking.aidl
index 4db47c9..d38c584 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Braking.aidl
@@ -31,21 +31,9 @@
 // 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.biometrics.face;
-@Backing(type="byte") @VintfStability
-enum SessionState {
-  IDLING = 0,
-  CLOSED = 1,
-  GENERATING_CHALLENGE = 2,
-  REVOKING_CHALLENGE = 3,
-  ENROLLING = 4,
-  AUTHENTICATING = 5,
-  DETECTING_INTERACTION = 6,
-  ENUMERATING_ENROLLMENTS = 7,
-  REMOVING_ENROLLMENTS = 8,
-  GETTING_FEATURES = 9,
-  SETTING_FEATURE = 10,
-  GETTING_AUTHENTICATOR_ID = 11,
-  INVALIDATING_AUTHENTICATOR_ID = 12,
-  RESETTING_LOCKOUT = 13,
+package android.hardware.vibrator;
+@Backing(type="int") @VintfStability
+enum Braking {
+  NONE = 0,
+  CLAB = 1,
 }
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/BrakingPwle.aidl
similarity index 78%
copy from biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
copy to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/BrakingPwle.aidl
index 4db47c9..fa7b43a 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/BrakingPwle.aidl
@@ -31,21 +31,9 @@
 // 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.biometrics.face;
-@Backing(type="byte") @VintfStability
-enum SessionState {
-  IDLING = 0,
-  CLOSED = 1,
-  GENERATING_CHALLENGE = 2,
-  REVOKING_CHALLENGE = 3,
-  ENROLLING = 4,
-  AUTHENTICATING = 5,
-  DETECTING_INTERACTION = 6,
-  ENUMERATING_ENROLLMENTS = 7,
-  REMOVING_ENROLLMENTS = 8,
-  GETTING_FEATURES = 9,
-  SETTING_FEATURE = 10,
-  GETTING_AUTHENTICATOR_ID = 11,
-  INVALIDATING_AUTHENTICATOR_ID = 12,
-  RESETTING_LOCKOUT = 13,
+package android.hardware.vibrator;
+@VintfStability
+parcelable BrakingPwle {
+  android.hardware.vibrator.Braking braking;
+  int duration;
 }
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositeEffect.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositeEffect.aidl
index 0995d2d..3be58a1 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositeEffect.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositeEffect.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositePrimitive.aidl
index 0b4b527..50de13f 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositePrimitive.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/CompositePrimitive.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Effect.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Effect.aidl
index 0d2b340..adf0f20 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Effect.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/Effect.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/EffectStrength.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/EffectStrength.aidl
index 808644a..af5e158 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/EffectStrength.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/EffectStrength.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl
index 1f2d946..b7afb66 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -50,6 +51,13 @@
   void alwaysOnDisable(in int id);
   float getResonantFrequency();
   float getQFactor();
+  float getFrequencyResolution();
+  float getFrequencyMinimum();
+  float[] getBandwidthAmplitudeMap();
+  int getPwlePrimitiveDurationMax();
+  int getPwleCompositionSizeMax();
+  android.hardware.vibrator.Braking[] getSupportedBraking();
+  void composePwle(in android.hardware.vibrator.PrimitivePwle[] composite, in android.hardware.vibrator.IVibratorCallback callback);
   const int CAP_ON_CALLBACK = 1;
   const int CAP_PERFORM_CALLBACK = 2;
   const int CAP_AMPLITUDE_CONTROL = 4;
@@ -59,4 +67,6 @@
   const int CAP_ALWAYS_ON_CONTROL = 64;
   const int CAP_GET_RESONANT_FREQUENCY = 128;
   const int CAP_GET_Q_FACTOR = 256;
+  const int CAP_FREQUENCY_CONTROL = 512;
+  const int CAP_COMPOSE_PWLE_EFFECTS = 1024;
 }
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorCallback.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorCallback.aidl
index f99ecc1..99d6d22 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorCallback.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorCallback.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl
index 8e3ac88..290c68d 100644
--- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PrimitivePwle.aidl
similarity index 78%
rename from biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
rename to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PrimitivePwle.aidl
index 4db47c9..584bcf4 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
+++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PrimitivePwle.aidl
@@ -31,21 +31,9 @@
 // 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.biometrics.face;
-@Backing(type="byte") @VintfStability
-enum SessionState {
-  IDLING = 0,
-  CLOSED = 1,
-  GENERATING_CHALLENGE = 2,
-  REVOKING_CHALLENGE = 3,
-  ENROLLING = 4,
-  AUTHENTICATING = 5,
-  DETECTING_INTERACTION = 6,
-  ENUMERATING_ENROLLMENTS = 7,
-  REMOVING_ENROLLMENTS = 8,
-  GETTING_FEATURES = 9,
-  SETTING_FEATURE = 10,
-  GETTING_AUTHENTICATOR_ID = 11,
-  INVALIDATING_AUTHENTICATOR_ID = 12,
-  RESETTING_LOCKOUT = 13,
+package android.hardware.vibrator;
+@VintfStability
+union PrimitivePwle {
+  android.hardware.vibrator.ActivePwle active;
+  android.hardware.vibrator.BrakingPwle braking;
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/ActivePwle.aidl b/vibrator/aidl/android/hardware/vibrator/ActivePwle.aidl
new file mode 100644
index 0000000..fd5f8d1
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/ActivePwle.aidl
@@ -0,0 +1,49 @@
+/*
+ * 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.vibrator;
+
+@VintfStability
+parcelable ActivePwle {
+    /**
+     * Amplitude ranging from 0.0 (inclusive) to 1.0 (inclusive)
+     * in units of output acceleration amplitude, not voltage amplitude.
+     *
+     * 0.0 represents no output acceleration amplitude
+     * 1.0 represents maximum output acceleration amplitude at resonant frequency
+     */
+    float startAmplitude;
+    /**
+     * Absolute frequency point in the units of hertz
+     */
+    float startFrequency;
+    /**
+     * Amplitude ranging from 0.0 (inclusive) to 1.0 (inclusive)
+     * in units of output acceleration amplitude, not voltage amplitude.
+     *
+     * 0.0 represents no output acceleration amplitude
+     * 1.0 represents maximum output acceleration amplitude at resonant frequency
+     */
+    float endAmplitude;
+    /**
+     * Absolute frequency point in the units of hertz
+     */
+    float endFrequency;
+    /**
+     * Total duration from start point to end point in the units of milliseconds
+     */
+    int duration;
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/Braking.aidl b/vibrator/aidl/android/hardware/vibrator/Braking.aidl
new file mode 100644
index 0000000..2bc51db
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/Braking.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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.vibrator;
+
+@VintfStability
+@Backing(type="int")
+enum Braking {
+    /**
+     * No braking mechanism used.
+     * This is the default if the hardware does not support any braking mechanism.
+     */
+    NONE,
+    /**
+     * Closed-loop active braking.
+     *
+     * This effect should produce a sharp, crisp end to the waveform
+     * Support is optional.
+     */
+    CLAB,
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/BrakingPwle.aidl b/vibrator/aidl/android/hardware/vibrator/BrakingPwle.aidl
new file mode 100644
index 0000000..00675ed
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/BrakingPwle.aidl
@@ -0,0 +1,37 @@
+/*
+ * 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.vibrator;
+
+import android.hardware.vibrator.Braking;
+
+/**
+ * BrakingPwle is defined as a segment of zero output acceleration amplitude of duration length.
+ *
+ * There should be no output acceleration and the vibrator should be off for the entire duration.
+ * If the hardware supports braking mechanism(s), they can be set here.
+ */
+@VintfStability
+parcelable BrakingPwle {
+    /**
+     * Braking mechanism applied to adjacent segments
+     */
+    Braking braking;
+    /**
+     * Total duration of zero output acceleration in the units of milliseconds.
+     */
+    int duration;
+}
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index cba76dc..592d151 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -17,10 +17,12 @@
 package android.hardware.vibrator;
 
 import android.hardware.vibrator.IVibratorCallback;
+import android.hardware.vibrator.Braking;
 import android.hardware.vibrator.Effect;
 import android.hardware.vibrator.EffectStrength;
 import android.hardware.vibrator.CompositeEffect;
 import android.hardware.vibrator.CompositePrimitive;
+import android.hardware.vibrator.PrimitivePwle;
 
 @VintfStability
 interface IVibrator {
@@ -60,6 +62,14 @@
      * Whether getQFactor is supported.
      */
     const int CAP_GET_Q_FACTOR = 1 << 8;
+    /**
+     * Whether frequency control is supported.
+     */
+    const int CAP_FREQUENCY_CONTROL = 1 << 9;
+    /**
+     * Whether composePwle is supported.
+     */
+    const int CAP_COMPOSE_PWLE_EFFECTS = 1 << 10;
 
     /**
      * Determine capabilities of the vibrator HAL (CAP_* mask)
@@ -240,18 +250,109 @@
     void alwaysOnDisable(in int id);
 
     /**
-     * Retrieve the measured resonant frequency of the actuator. This may not be supported
-     * and this support is reflected in getCapabilities (CAP_GET_RESONANT_FREQUENCY)
+     * Retrieve the measured resonant frequency of the actuator.
      *
-     * @return Measured resonant frequency in Hz.
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_GET_RESONANT_FREQUENCY)
+     *
+     * @return Measured resonant frequency in Hz. Non-zero value if supported,
+     *         or value should be ignored if not supported.
      */
     float getResonantFrequency();
 
     /**
-     * Retrieve the measured Q factor. This may not be supported
-     * and this support is reflected in getCapabilities (CAP_GET_Q_FACTOR)
+     * Retrieve the measured Q factor.
      *
-     * @return Measured Q factor.
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_GET_Q_FACTOR)
+     *
+     * @return Measured Q factor. Non-zero value if supported, or value should be
+     *         ignored if not supported.
      */
     float getQFactor();
+
+    /**
+     * Retrieve the frequency resolution used in getBandwidthAmplitudeMap() in units of hertz
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_FREQUENCY_CONTROL).
+     *
+     * @return The frequency resolution of the bandwidth amplitude map.
+     *         Non-zero value if supported, or value should be ignored if not supported.
+     */
+    float getFrequencyResolution();
+
+    /**
+     * Retrieve the minimum allowed frequency in units of hertz
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_FREQUENCY_CONTROL).
+     *
+     * @return The minimum frequency allowed. Non-zero value if supported,
+     *         or value should be ignored if not supported.
+     */
+    float getFrequencyMinimum();
+
+    /**
+     * Retrieve the output acceleration amplitude values per frequency supported
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_FREQUENCY_CONTROL).
+     *
+     * The mapping is represented as a list of amplitude values in the inclusive range [0.0, 1.0].
+     * The first value represents the amplitude at the frequency returned by getFrequencyMinimum().
+     * Each subsequent element is the amplitude at the next supported frequency, in increments
+     * of getFrequencyResolution(). The value returned by getResonantFrequency() must be
+     * represented in the returned list.
+     *
+     * @return The maximum output acceleration amplitude for each supported frequency,
+     *         starting at getMinimumFrequency()
+     */
+    float[] getBandwidthAmplitudeMap();
+
+    /**
+     * Retrieve the maximum duration allowed for any primitive PWLE in units of milliseconds.
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS).
+     *
+     * @return The maximum duration allowed for a single PrimitivePwle.
+     *         Non-zero value if supported, or value should be ignored if not supported.
+     */
+    int getPwlePrimitiveDurationMax();
+
+    /**
+     * Retrieve the maximum count for allowed PWLEs in one composition.
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS).
+     *
+     * @return The maximum count allowed. Non-zero value if supported,
+     *         or value should be ignored if not supported.
+     */
+    int getPwleCompositionSizeMax();
+
+    /**
+     * List of supported braking mechanism.
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS).
+     * Implementations are optional but encouraged if available.
+     *
+     * @return The braking mechanisms which are supported by the composePwle API.
+     */
+    Braking[] getSupportedBraking();
+
+    /**
+     * Fire off a string of PWLEs.
+     *
+     * This may not be supported and this support is reflected in
+     * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS).
+     *
+     * Doing this operation while the vibrator is already on is undefined behavior. Clients should
+     * explicitly call off. IVibratorCallback.onComplete() support is required for this API.
+     *
+     * @param composite Array of PWLEs.
+     */
+    void composePwle(in PrimitivePwle[] composite, in IVibratorCallback callback);
 }
diff --git a/vibrator/aidl/android/hardware/vibrator/PrimitivePwle.aidl b/vibrator/aidl/android/hardware/vibrator/PrimitivePwle.aidl
new file mode 100644
index 0000000..813c7dc
--- /dev/null
+++ b/vibrator/aidl/android/hardware/vibrator/PrimitivePwle.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.vibrator;
+
+import android.hardware.vibrator.ActivePwle;
+import android.hardware.vibrator.BrakingPwle;
+
+@VintfStability
+union PrimitivePwle {
+    ActivePwle active;
+    BrakingPwle braking;
+}
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index bf61bfe..c6682b3 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -26,9 +26,16 @@
 
 static constexpr int32_t kComposeDelayMaxMs = 1000;
 static constexpr int32_t kComposeSizeMax = 256;
+static constexpr int32_t kComposePwleSizeMax = 127;
 
 static constexpr float kResonantFrequency = 150.0;
 static constexpr float kQFactor = 11.0;
+static constexpr int32_t COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS = 16383;
+static constexpr float PWLE_LEVEL_MIN = 0.0;
+static constexpr float PWLE_LEVEL_MAX = 0.98256;
+static constexpr float PWLE_FREQUENCY_RESOLUTION_HZ = 1.0;
+static constexpr float PWLE_FREQUENCY_MIN_HZ = 140.0;
+static constexpr float PWLE_FREQUENCY_MAX_HZ = 160.0;
 
 ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
     LOG(INFO) << "Vibrator reporting capabilities";
@@ -36,7 +43,8 @@
                     IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL |
                     IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS |
                     IVibrator::CAP_ALWAYS_ON_CONTROL | IVibrator::CAP_GET_RESONANT_FREQUENCY |
-                    IVibrator::CAP_GET_Q_FACTOR;
+                    IVibrator::CAP_GET_Q_FACTOR | IVibrator::CAP_FREQUENCY_CONTROL |
+                    IVibrator::CAP_COMPOSE_PWLE_EFFECTS;
     return ndk::ScopedAStatus::ok();
 }
 
@@ -215,6 +223,169 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Vibrator::getFrequencyResolution(float *freqResolutionHz) {
+    *freqResolutionHz = PWLE_FREQUENCY_RESOLUTION_HZ;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float *freqMinimumHz) {
+    *freqMinimumHz = PWLE_FREQUENCY_MIN_HZ;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float> *_aidl_return) {
+    // A valid array should be of size:
+    //     (PWLE_FREQUENCY_MAX_HZ - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ
+    *_aidl_return = {0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.10,
+                     0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.20};
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t *durationMs) {
+    *durationMs = COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t *maxSize) {
+    *maxSize = kComposePwleSizeMax;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking> *supported) {
+    *supported = {
+            Braking::NONE,
+            Braking::CLAB,
+    };
+    return ndk::ScopedAStatus::ok();
+}
+
+void resetPreviousEndAmplitudeEndFrequency(float &prevEndAmplitude, float &prevEndFrequency) {
+    const float reset = -1.0;
+    prevEndAmplitude = reset;
+    prevEndFrequency = reset;
+}
+
+void incrementIndex(int &index) {
+    index += 1;
+}
+
+void constructActiveDefaults(std::ostringstream &pwleBuilder, const int &segmentIdx) {
+    pwleBuilder << ",C" << segmentIdx << ":1";
+    pwleBuilder << ",B" << segmentIdx << ":0";
+    pwleBuilder << ",AR" << segmentIdx << ":0";
+    pwleBuilder << ",V" << segmentIdx << ":0";
+}
+
+void constructActiveSegment(std::ostringstream &pwleBuilder, const int &segmentIdx, int duration,
+                            float amplitude, float frequency) {
+    pwleBuilder << ",T" << segmentIdx << ":" << duration;
+    pwleBuilder << ",L" << segmentIdx << ":" << amplitude;
+    pwleBuilder << ",F" << segmentIdx << ":" << frequency;
+    constructActiveDefaults(pwleBuilder, segmentIdx);
+}
+
+void constructBrakingSegment(std::ostringstream &pwleBuilder, const int &segmentIdx, int duration,
+                             Braking brakingType) {
+    pwleBuilder << ",T" << segmentIdx << ":" << duration;
+    pwleBuilder << ",L" << segmentIdx << ":" << 0;
+    pwleBuilder << ",F" << segmentIdx << ":" << 0;
+    pwleBuilder << ",C" << segmentIdx << ":0";
+    pwleBuilder << ",B" << segmentIdx << ":"
+                << static_cast<std::underlying_type<Braking>::type>(brakingType);
+    pwleBuilder << ",AR" << segmentIdx << ":0";
+    pwleBuilder << ",V" << segmentIdx << ":0";
+}
+
+ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &composite,
+                                         const std::shared_ptr<IVibratorCallback> &callback) {
+    std::ostringstream pwleBuilder;
+    std::string pwleQueue;
+
+    int compositionSizeMax;
+    getPwleCompositionSizeMax(&compositionSizeMax);
+    if (composite.size() <= 0 || composite.size() > compositionSizeMax) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    float prevEndAmplitude;
+    float prevEndFrequency;
+    resetPreviousEndAmplitudeEndFrequency(prevEndAmplitude, prevEndFrequency);
+
+    int segmentIdx = 0;
+    uint32_t totalDuration = 0;
+
+    pwleBuilder << "S:0,WF:4,RP:0,WT:0";
+
+    for (auto &e : composite) {
+        switch (e.getTag()) {
+            case PrimitivePwle::active: {
+                auto active = e.get<PrimitivePwle::active>();
+                if (active.duration < 0 ||
+                    active.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) {
+                    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+                }
+                if (active.startAmplitude < PWLE_LEVEL_MIN ||
+                    active.startAmplitude > PWLE_LEVEL_MAX ||
+                    active.endAmplitude < PWLE_LEVEL_MIN || active.endAmplitude > PWLE_LEVEL_MAX) {
+                    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+                }
+                if (active.startFrequency < PWLE_FREQUENCY_MIN_HZ ||
+                    active.startFrequency > PWLE_FREQUENCY_MAX_HZ ||
+                    active.endFrequency < PWLE_FREQUENCY_MIN_HZ ||
+                    active.endFrequency > PWLE_FREQUENCY_MAX_HZ) {
+                    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+                }
+
+                if (!((active.startAmplitude == prevEndAmplitude) &&
+                      (active.startFrequency == prevEndFrequency))) {
+                    constructActiveSegment(pwleBuilder, segmentIdx, 0, active.startAmplitude,
+                                           active.startFrequency);
+                    incrementIndex(segmentIdx);
+                }
+
+                constructActiveSegment(pwleBuilder, segmentIdx, active.duration,
+                                       active.endAmplitude, active.endFrequency);
+                incrementIndex(segmentIdx);
+
+                prevEndAmplitude = active.endAmplitude;
+                prevEndFrequency = active.endFrequency;
+                totalDuration += active.duration;
+                break;
+            }
+            case PrimitivePwle::braking: {
+                auto braking = e.get<PrimitivePwle::braking>();
+                if (braking.braking > Braking::CLAB) {
+                    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+                }
+                if (braking.duration > COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS) {
+                    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+                }
+
+                constructBrakingSegment(pwleBuilder, segmentIdx, 0, braking.braking);
+                incrementIndex(segmentIdx);
+
+                constructBrakingSegment(pwleBuilder, segmentIdx, braking.duration, braking.braking);
+                incrementIndex(segmentIdx);
+
+                resetPreviousEndAmplitudeEndFrequency(prevEndAmplitude, prevEndFrequency);
+                totalDuration += braking.duration;
+                break;
+            }
+        }
+    }
+
+    std::thread([=] {
+        LOG(INFO) << "Starting composePwle on another thread";
+        usleep(totalDuration * 1000);
+        if (callback != nullptr) {
+            LOG(INFO) << "Notifying compose PWLE complete";
+            callback->onComplete();
+        }
+    }).detach();
+
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace vibrator
 }  // namespace hardware
 }  // namespace android
diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
index a2af963..4203bf2 100644
--- a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
+++ b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
@@ -46,6 +46,15 @@
     ndk::ScopedAStatus alwaysOnDisable(int32_t id) override;
     ndk::ScopedAStatus getResonantFrequency(float *resonantFreqHz) override;
     ndk::ScopedAStatus getQFactor(float *qFactor) override;
+    ndk::ScopedAStatus getFrequencyResolution(float *freqResolutionHz) override;
+    ndk::ScopedAStatus getFrequencyMinimum(float *freqMinimumHz) override;
+    ndk::ScopedAStatus getBandwidthAmplitudeMap(std::vector<float> *_aidl_return) override;
+    ndk::ScopedAStatus getPwlePrimitiveDurationMax(int32_t *durationMs) override;
+    ndk::ScopedAStatus getPwleCompositionSizeMax(int32_t *maxSize) override;
+    ndk::ScopedAStatus getSupportedBraking(std::vector<Braking>* supported) override;
+    ndk::ScopedAStatus composePwle(const std::vector<PrimitivePwle> &composite,
+                                   const std::shared_ptr<IVibratorCallback> &callback) override;
+
 };
 
 }  // namespace vibrator
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index 2540d0b..4d03ebf 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -15,7 +15,6 @@
  */
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
-
 #include <android/hardware/vibrator/BnVibratorCallback.h>
 #include <android/hardware/vibrator/IVibrator.h>
 #include <android/hardware/vibrator/IVibratorManager.h>
@@ -29,13 +28,17 @@
 using android::sp;
 using android::String16;
 using android::binder::Status;
+using android::hardware::vibrator::ActivePwle;
 using android::hardware::vibrator::BnVibratorCallback;
+using android::hardware::vibrator::Braking;
+using android::hardware::vibrator::BrakingPwle;
 using android::hardware::vibrator::CompositeEffect;
 using android::hardware::vibrator::CompositePrimitive;
 using android::hardware::vibrator::Effect;
 using android::hardware::vibrator::EffectStrength;
 using android::hardware::vibrator::IVibrator;
 using android::hardware::vibrator::IVibratorManager;
+using android::hardware::vibrator::PrimitivePwle;
 using std::chrono::high_resolution_clock;
 
 const std::vector<Effect> kEffects{android::enum_range<Effect>().begin(),
@@ -44,32 +47,32 @@
                                                    android::enum_range<EffectStrength>().end()};
 
 const std::vector<Effect> kInvalidEffects = {
-        static_cast<Effect>(static_cast<int32_t>(kEffects.front()) - 1),
-        static_cast<Effect>(static_cast<int32_t>(kEffects.back()) + 1),
+    static_cast<Effect>(static_cast<int32_t>(kEffects.front()) - 1),
+    static_cast<Effect>(static_cast<int32_t>(kEffects.back()) + 1),
 };
 
 const std::vector<EffectStrength> kInvalidEffectStrengths = {
-        static_cast<EffectStrength>(static_cast<int8_t>(kEffectStrengths.front()) - 1),
-        static_cast<EffectStrength>(static_cast<int8_t>(kEffectStrengths.back()) + 1),
+    static_cast<EffectStrength>(static_cast<int8_t>(kEffectStrengths.front()) - 1),
+    static_cast<EffectStrength>(static_cast<int8_t>(kEffectStrengths.back()) + 1),
 };
 
 const std::vector<CompositePrimitive> kCompositePrimitives{
-        android::enum_range<CompositePrimitive>().begin(),
-        android::enum_range<CompositePrimitive>().end()};
+    android::enum_range<CompositePrimitive>().begin(),
+    android::enum_range<CompositePrimitive>().end()};
 
 const std::vector<CompositePrimitive> kOptionalPrimitives = {
-        CompositePrimitive::THUD,
-        CompositePrimitive::SPIN,
+    CompositePrimitive::THUD,
+    CompositePrimitive::SPIN,
 };
 
 const std::vector<CompositePrimitive> kInvalidPrimitives = {
-        static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.front()) - 1),
-        static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.back()) + 1),
+    static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.front()) - 1),
+    static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.back()) + 1),
 };
 
 class CompletionCallback : public BnVibratorCallback {
   public:
-    CompletionCallback(const std::function<void()>& callback) : mCallback(callback) {}
+    CompletionCallback(const std::function<void()> &callback) : mCallback(callback) {}
     Status onComplete() override {
         mCallback();
         return Status::ok();
@@ -109,6 +112,89 @@
     int32_t capabilities;
 };
 
+static float getResonantFrequencyHz(sp<IVibrator> vibrator, int32_t capabilities) {
+    float resonantFrequencyHz;
+    Status status = vibrator->getResonantFrequency(&resonantFrequencyHz);
+    if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) {
+        EXPECT_GT(resonantFrequencyHz, 0);
+        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+    } else {
+        EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+    }
+    return resonantFrequencyHz;
+}
+
+static float getFrequencyResolutionHz(sp<IVibrator> vibrator, int32_t capabilities) {
+    float freqResolutionHz;
+    Status status = vibrator->getFrequencyResolution(&freqResolutionHz);
+    if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
+        EXPECT_GT(freqResolutionHz, 0);
+        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+    } else {
+        EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+    }
+    return freqResolutionHz;
+}
+
+static float getFrequencyMinimumHz(sp<IVibrator> vibrator, int32_t capabilities) {
+    float freqMinimumHz;
+    Status status = vibrator->getFrequencyMinimum(&freqMinimumHz);
+    if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
+        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+
+        float resonantFrequencyHz = getResonantFrequencyHz(vibrator, capabilities);
+
+        EXPECT_GT(freqMinimumHz, 0);
+        EXPECT_LE(freqMinimumHz, resonantFrequencyHz);
+    } else {
+        EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+    }
+    return freqMinimumHz;
+}
+
+static float getFrequencyMaximumHz(sp<IVibrator> vibrator, int32_t capabilities) {
+    std::vector<float> bandwidthAmplitudeMap;
+    Status status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
+    if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
+        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+    } else {
+        EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+    }
+
+    float freqMaximumHz =
+        (bandwidthAmplitudeMap.size() * getFrequencyResolutionHz(vibrator, capabilities)) +
+        getFrequencyMinimumHz(vibrator, capabilities);
+    return freqMaximumHz;
+}
+
+static float getAmplitudeMin() {
+    return 0.0;
+}
+
+static float getAmplitudeMax() {
+    return 1.0;
+}
+
+static ActivePwle composeValidActivePwle(sp<IVibrator> vibrator, int32_t capabilities) {
+    float frequencyHz;
+    if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) {
+        frequencyHz = getResonantFrequencyHz(vibrator, capabilities);
+    } else if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
+        frequencyHz = getFrequencyMinimumHz(vibrator, capabilities);
+    } else {
+        frequencyHz = 150.0;  // default value commonly used
+    }
+
+    ActivePwle active;
+    active.startAmplitude = (getAmplitudeMin() + getAmplitudeMax()) / 2;
+    active.startFrequency = frequencyHz;
+    active.endAmplitude = (getAmplitudeMin() + getAmplitudeMax()) / 2;
+    active.endFrequency = frequencyHz;
+    active.duration = 1000;
+
+    return active;
+}
+
 TEST_P(VibratorAidl, OnThenOffBeforeTimeout) {
     EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk());
     sleep(1);
@@ -116,12 +202,13 @@
 }
 
 TEST_P(VibratorAidl, OnWithCallback) {
-    if (!(capabilities & IVibrator::CAP_ON_CALLBACK)) return;
+    if (!(capabilities & IVibrator::CAP_ON_CALLBACK))
+        return;
 
     std::promise<void> completionPromise;
     std::future<void> completionFuture{completionPromise.get_future()};
     sp<CompletionCallback> callback =
-            new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+        new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
     uint32_t durationMs = 250;
     std::chrono::milliseconds timeout{durationMs * 2};
     EXPECT_TRUE(vibrator->on(durationMs, callback).isOk());
@@ -142,7 +229,7 @@
 
     for (Effect effect : kEffects) {
         bool isEffectSupported =
-                std::find(supported.begin(), supported.end(), effect) != supported.end();
+            std::find(supported.begin(), supported.end(), effect) != supported.end();
 
         for (EffectStrength strength : kEffectStrengths) {
             int32_t lengthMs = 0;
@@ -154,27 +241,28 @@
                 usleep(lengthMs * 1000);
             } else {
                 EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION)
-                        << toString(effect) << " " << toString(strength);
+                    << toString(effect) << " " << toString(strength);
             }
         }
     }
 }
 
 TEST_P(VibratorAidl, ValidateEffectWithCallback) {
-    if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK)) return;
+    if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK))
+        return;
 
     std::vector<Effect> supported;
     ASSERT_TRUE(vibrator->getSupportedEffects(&supported).isOk());
 
     for (Effect effect : kEffects) {
         bool isEffectSupported =
-                std::find(supported.begin(), supported.end(), effect) != supported.end();
+            std::find(supported.begin(), supported.end(), effect) != supported.end();
 
         for (EffectStrength strength : kEffectStrengths) {
             std::promise<void> completionPromise;
             std::future<void> completionFuture{completionPromise.get_future()};
             sp<CompletionCallback> callback =
-                    new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+                new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
             int lengthMs = 0;
             Status status = vibrator->perform(effect, strength, callback, &lengthMs);
 
@@ -185,7 +273,8 @@
                 EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
             }
 
-            if (!status.isOk()) continue;
+            if (!status.isOk())
+                continue;
 
             std::chrono::milliseconds timeout{lengthMs * 2};
             EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
@@ -194,7 +283,8 @@
 }
 
 TEST_P(VibratorAidl, ValidateEffectWithCallbackNotSupported) {
-    if (capabilities & IVibrator::CAP_PERFORM_CALLBACK) return;
+    if (capabilities & IVibrator::CAP_PERFORM_CALLBACK)
+        return;
 
     for (Effect effect : kEffects) {
         for (EffectStrength strength : kEffectStrengths) {
@@ -212,7 +302,7 @@
             int32_t lengthMs;
             Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
             EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION)
-                    << toString(effect) << " " << toString(strength);
+                << toString(effect) << " " << toString(strength);
         }
     }
     for (Effect effect : kEffects) {
@@ -220,7 +310,7 @@
             int32_t lengthMs;
             Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
             EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION)
-                    << toString(effect) << " " << toString(strength);
+                << toString(effect) << " " << toString(strength);
         }
     }
 }
@@ -261,7 +351,7 @@
 
 TEST_P(VibratorAidl, ExternalAmplitudeControl) {
     const bool supportsExternalAmplitudeControl =
-            (capabilities & IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) > 0;
+        (capabilities & IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) > 0;
 
     if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) {
         EXPECT_TRUE(vibrator->setExternalControl(true).isOk());
@@ -293,10 +383,10 @@
 
         for (auto primitive : kCompositePrimitives) {
             bool isPrimitiveSupported =
-                    std::find(supported.begin(), supported.end(), primitive) != supported.end();
+                std::find(supported.begin(), supported.end(), primitive) != supported.end();
             bool isPrimitiveOptional =
-                    std::find(kOptionalPrimitives.begin(), kOptionalPrimitives.end(), primitive) !=
-                    kOptionalPrimitives.end();
+                std::find(kOptionalPrimitives.begin(), kOptionalPrimitives.end(), primitive) !=
+                kOptionalPrimitives.end();
 
             EXPECT_TRUE(isPrimitiveSupported || isPrimitiveOptional) << toString(primitive);
         }
@@ -310,7 +400,7 @@
 
         for (auto primitive : kCompositePrimitives) {
             bool isPrimitiveSupported =
-                    std::find(supported.begin(), supported.end(), primitive) != supported.end();
+                std::find(supported.begin(), supported.end(), primitive) != supported.end();
             int32_t duration;
 
             Status status = vibrator->getPrimitiveDuration(primitive, &duration);
@@ -366,7 +456,7 @@
 
         for (auto primitive : kCompositePrimitives) {
             bool isPrimitiveSupported =
-                    std::find(supported.begin(), supported.end(), primitive) != supported.end();
+                std::find(supported.begin(), supported.end(), primitive) != supported.end();
 
             if (!isPrimitiveSupported) {
                 unsupported.push_back(primitive);
@@ -376,7 +466,7 @@
         for (auto primitive : unsupported) {
             std::vector<CompositeEffect> composite(1);
 
-            for (auto& effect : composite) {
+            for (auto &effect : composite) {
                 effect.delayMs = 0;
                 effect.primitive = primitive;
                 effect.scale = 1.0f;
@@ -391,7 +481,7 @@
 TEST_P(VibratorAidl, ComposeScaleBoundary) {
     if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
         std::vector<CompositeEffect> composite(1);
-        CompositeEffect& effect = composite[0];
+        CompositeEffect &effect = composite[0];
 
         effect.delayMs = 0;
         effect.primitive = CompositePrimitive::CLICK;
@@ -463,8 +553,6 @@
 }
 
 TEST_P(VibratorAidl, ComposeCallback) {
-    constexpr std::chrono::milliseconds allowedLatency{10};
-
     if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
         std::vector<CompositePrimitive> supported;
 
@@ -478,7 +566,7 @@
             std::promise<void> completionPromise;
             std::future<void> completionFuture{completionPromise.get_future()};
             sp<CompletionCallback> callback =
-                    new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+                new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
             CompositeEffect effect;
             std::vector<CompositeEffect> composite;
             int32_t durationMs;
@@ -493,21 +581,19 @@
 
             EXPECT_EQ(Status::EX_NONE,
                       vibrator->getPrimitiveDuration(primitive, &durationMs).exceptionCode())
-                    << toString(primitive);
+                << toString(primitive);
             duration = std::chrono::milliseconds(durationMs);
 
-            EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, callback).exceptionCode())
-                    << toString(primitive);
             start = high_resolution_clock::now();
+            EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, callback).exceptionCode())
+                << toString(primitive);
 
-            EXPECT_EQ(completionFuture.wait_for(duration + allowedLatency),
-                      std::future_status::ready)
-                    << toString(primitive);
+            EXPECT_EQ(completionFuture.wait_for(duration * 2), std::future_status::ready)
+                << toString(primitive);
             end = high_resolution_clock::now();
 
             elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
-            EXPECT_LE(elapsed.count(), (duration + allowedLatency).count()) << toString(primitive);
-            EXPECT_GE(elapsed.count(), (duration - allowedLatency).count()) << toString(primitive);
+            EXPECT_GE(elapsed.count(), duration.count()) << toString(primitive);
         }
     }
 }
@@ -519,17 +605,17 @@
 
         for (Effect effect : kEffects) {
             bool isEffectSupported =
-                    std::find(supported.begin(), supported.end(), effect) != supported.end();
+                std::find(supported.begin(), supported.end(), effect) != supported.end();
 
             for (EffectStrength strength : kEffectStrengths) {
                 Status status = vibrator->alwaysOnEnable(0, effect, strength);
 
                 if (isEffectSupported) {
                     EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
-                            << toString(effect) << " " << toString(strength);
+                        << toString(effect) << " " << toString(strength);
                 } else {
                     EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode())
-                            << toString(effect) << " " << toString(strength);
+                        << toString(effect) << " " << toString(strength);
                 }
             }
         }
@@ -539,27 +625,253 @@
 }
 
 TEST_P(VibratorAidl, GetResonantFrequency) {
-    float resonantFrequency;
-    Status status = vibrator->getResonantFrequency(&resonantFrequency);
-    if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) {
-        ASSERT_NE(resonantFrequency, 0);
-        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
-    } else {
-        EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
-    }
+    getResonantFrequencyHz(vibrator, capabilities);
 }
 
 TEST_P(VibratorAidl, GetQFactor) {
     float qFactor;
     Status status = vibrator->getQFactor(&qFactor);
     if (capabilities & IVibrator::CAP_GET_Q_FACTOR) {
-        ASSERT_NE(qFactor, 0);
+        ASSERT_GT(qFactor, 0);
         EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
     } else {
         EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
     }
 }
 
+TEST_P(VibratorAidl, GetFrequencyResolution) {
+    getFrequencyResolutionHz(vibrator, capabilities);
+}
+
+TEST_P(VibratorAidl, GetFrequencyMinimum) {
+    getFrequencyMinimumHz(vibrator, capabilities);
+}
+
+TEST_P(VibratorAidl, GetBandwidthAmplitudeMap) {
+    std::vector<float> bandwidthAmplitudeMap;
+    Status status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap);
+    if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) {
+        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+        ASSERT_FALSE(bandwidthAmplitudeMap.empty());
+
+        int minMapSize = (getResonantFrequencyHz(vibrator, capabilities) -
+                          getFrequencyMinimumHz(vibrator, capabilities)) /
+                         getFrequencyResolutionHz(vibrator, capabilities);
+        ASSERT_GT(bandwidthAmplitudeMap.size(), minMapSize);
+
+        for (float e : bandwidthAmplitudeMap) {
+            ASSERT_GE(e, 0.0);
+            ASSERT_LE(e, 1.0);
+        }
+    } else {
+        EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+    }
+}
+
+TEST_P(VibratorAidl, GetPwlePrimitiveDurationMax) {
+    int32_t durationMs;
+    Status status = vibrator->getPwlePrimitiveDurationMax(&durationMs);
+    if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+        ASSERT_NE(durationMs, 0);
+        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+    } else {
+        EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+    }
+}
+
+TEST_P(VibratorAidl, GetPwleCompositionSizeMax) {
+    int32_t maxSize;
+    Status status = vibrator->getPwleCompositionSizeMax(&maxSize);
+    if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+        ASSERT_NE(maxSize, 0);
+        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+    } else {
+        EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+    }
+}
+
+TEST_P(VibratorAidl, GetSupportedBraking) {
+    std::vector<Braking> supported;
+    Status status = vibrator->getSupportedBraking(&supported);
+    if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+        bool isDefaultNoneSupported =
+            std::find(supported.begin(), supported.end(), Braking::NONE) != supported.end();
+        ASSERT_TRUE(isDefaultNoneSupported);
+        EXPECT_EQ(status.exceptionCode(), Status::EX_NONE);
+    } else {
+        EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+    }
+}
+
+TEST_P(VibratorAidl, ComposeValidPwle) {
+    if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+        ActivePwle active = composeValidActivePwle(vibrator, capabilities);
+
+        std::vector<Braking> supported;
+        ASSERT_TRUE(vibrator->getSupportedBraking(&supported).isOk());
+        bool isClabSupported =
+            std::find(supported.begin(), supported.end(), Braking::CLAB) != supported.end();
+        BrakingPwle braking;
+        braking.braking = isClabSupported ? Braking::CLAB : Braking::NONE;
+        braking.duration = 100;
+
+        std::vector<PrimitivePwle> pwleQueue;
+        PrimitivePwle pwle;
+        pwle = active;
+        pwleQueue.emplace_back(std::move(pwle));
+        pwle = braking;
+        pwleQueue.emplace_back(std::move(pwle));
+        pwle = active;
+        pwleQueue.emplace_back(std::move(pwle));
+
+        EXPECT_EQ(Status::EX_NONE, vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
+        vibrator->off();
+    }
+}
+
+TEST_P(VibratorAidl, ComposeValidPwleWithCallback) {
+    if (!((capabilities & IVibrator::CAP_ON_CALLBACK) &&
+          (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS)))
+        return;
+
+    std::promise<void> completionPromise;
+    std::future<void> completionFuture{completionPromise.get_future()};
+    sp<CompletionCallback> callback =
+        new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+    uint32_t durationMs = 2100;  // Sum of 2 active and 1 braking below
+    std::chrono::milliseconds timeout{durationMs * 2};
+
+    ActivePwle active = composeValidActivePwle(vibrator, capabilities);
+
+    std::vector<Braking> supported;
+    ASSERT_TRUE(vibrator->getSupportedBraking(&supported).isOk());
+    bool isClabSupported =
+        std::find(supported.begin(), supported.end(), Braking::CLAB) != supported.end();
+    BrakingPwle braking;
+    braking.braking = isClabSupported ? Braking::CLAB : Braking::NONE;
+    braking.duration = 100;
+
+    std::vector<PrimitivePwle> pwleQueue;
+    PrimitivePwle pwle;
+    pwle = active;
+    pwleQueue.emplace_back(std::move(pwle));
+    pwle = braking;
+    pwleQueue.emplace_back(std::move(pwle));
+    pwle = active;
+    pwleQueue.emplace_back(std::move(pwle));
+
+    EXPECT_TRUE(vibrator->composePwle(pwleQueue, callback).isOk());
+    EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
+    EXPECT_TRUE(vibrator->off().isOk());
+}
+
+TEST_P(VibratorAidl, ComposePwleSegmentBoundary) {
+    if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+        std::vector<PrimitivePwle> pwleQueue;
+        // test empty queue
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+                  vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
+        vibrator->off();
+
+        ActivePwle active = composeValidActivePwle(vibrator, capabilities);
+
+        PrimitivePwle pwle;
+        pwle = active;
+        int segmentCountMax;
+        vibrator->getPwleCompositionSizeMax(&segmentCountMax);
+
+        // Create PWLE queue with more segments than allowed
+        for (int i = 0; i < segmentCountMax + 10; i++) {
+            pwleQueue.emplace_back(std::move(pwle));
+        }
+
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+                  vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
+        vibrator->off();
+    }
+}
+
+TEST_P(VibratorAidl, ComposePwleAmplitudeParameterBoundary) {
+    if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+        ActivePwle active = composeValidActivePwle(vibrator, capabilities);
+        active.startAmplitude = getAmplitudeMax() + 1.0;  // Amplitude greater than allowed
+        active.endAmplitude = getAmplitudeMax() + 1.0;    // Amplitude greater than allowed
+
+        std::vector<PrimitivePwle> pwleQueueGreater;
+        PrimitivePwle pwle;
+        pwle = active;
+        pwleQueueGreater.emplace_back(std::move(pwle));
+
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+                  vibrator->composePwle(pwleQueueGreater, nullptr).exceptionCode());
+        vibrator->off();
+
+        active.startAmplitude = getAmplitudeMin() - 1.0;  // Amplitude less than allowed
+        active.endAmplitude = getAmplitudeMin() - 1.0;    // Amplitude less than allowed
+
+        std::vector<PrimitivePwle> pwleQueueLess;
+        pwle = active;
+        pwleQueueLess.emplace_back(std::move(pwle));
+
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+                  vibrator->composePwle(pwleQueueLess, nullptr).exceptionCode());
+        vibrator->off();
+    }
+}
+
+TEST_P(VibratorAidl, ComposePwleFrequencyParameterBoundary) {
+    if ((capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) &&
+        (capabilities & IVibrator::CAP_FREQUENCY_CONTROL)) {
+        float freqMinimumHz = getFrequencyMinimumHz(vibrator, capabilities);
+        float freqMaximumHz = getFrequencyMaximumHz(vibrator, capabilities);
+        float freqResolutionHz = getFrequencyResolutionHz(vibrator, capabilities);
+
+        ActivePwle active = composeValidActivePwle(vibrator, capabilities);
+        active.startFrequency =
+            freqMaximumHz + freqResolutionHz;                    // Frequency greater than allowed
+        active.endFrequency = freqMaximumHz + freqResolutionHz;  // Frequency greater than allowed
+
+        std::vector<PrimitivePwle> pwleQueueGreater;
+        PrimitivePwle pwle;
+        pwle = active;
+        pwleQueueGreater.emplace_back(std::move(pwle));
+
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+                  vibrator->composePwle(pwleQueueGreater, nullptr).exceptionCode());
+        vibrator->off();
+
+        active.startFrequency = freqMinimumHz - freqResolutionHz;  // Frequency less than allowed
+        active.endFrequency = freqMinimumHz - freqResolutionHz;    // Frequency less than allowed
+
+        std::vector<PrimitivePwle> pwleQueueLess;
+        pwle = active;
+        pwleQueueLess.emplace_back(std::move(pwle));
+
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+                  vibrator->composePwle(pwleQueueLess, nullptr).exceptionCode());
+        vibrator->off();
+    }
+}
+
+TEST_P(VibratorAidl, ComposePwleSegmentDurationBoundary) {
+    if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) {
+        ActivePwle active = composeValidActivePwle(vibrator, capabilities);
+
+        int segmentDurationMaxMs;
+        vibrator->getPwlePrimitiveDurationMax(&segmentDurationMaxMs);
+        active.duration = segmentDurationMaxMs + 10;  // Segment duration greater than allowed
+
+        std::vector<PrimitivePwle> pwleQueue;
+        PrimitivePwle pwle;
+        pwle = active;
+        pwleQueue.emplace_back(std::move(pwle));
+
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+                  vibrator->composePwle(pwleQueue, nullptr).exceptionCode());
+        vibrator->off();
+    }
+}
+
 std::vector<std::tuple<int32_t, int32_t>> GenerateVibratorMapping() {
     std::vector<std::tuple<int32_t, int32_t>> tuples;
     auto managerAidlNames = android::getAidlHalInstanceNames(IVibratorManager::descriptor);
@@ -569,7 +881,7 @@
         auto managerName = String16(managerAidlNames[i].c_str());
         auto vibratorManager = android::waitForDeclaredService<IVibratorManager>(managerName);
         if (vibratorManager->getVibratorIds(&vibratorIds).isOk()) {
-            for (auto& vibratorId : vibratorIds) {
+            for (auto &vibratorId : vibratorIds) {
                 tuples.push_back(std::make_tuple(i, vibratorId));
             }
         }
@@ -583,8 +895,8 @@
     return tuples;
 }
 
-std::string PrintGeneratedTest(const testing::TestParamInfo<VibratorAidl::ParamType>& info) {
-    const auto& [managerIdx, vibratorId] = info.param;
+std::string PrintGeneratedTest(const testing::TestParamInfo<VibratorAidl::ParamType> &info) {
+    const auto &[managerIdx, vibratorId] = info.param;
     if (managerIdx < 0) {
         return std::string("TOP_LEVEL_VIBRATOR_") + std::to_string(vibratorId);
     }
@@ -596,7 +908,7 @@
 INSTANTIATE_TEST_SUITE_P(Vibrator, VibratorAidl, testing::ValuesIn(GenerateVibratorMapping()),
                          PrintGeneratedTest);
 
-int main(int argc, char** argv) {
+int main(int argc, char **argv) {
     ::testing::InitGoogleTest(&argc, argv);
     ProcessState::self()->setThreadPoolMaxThreadCount(1);
     ProcessState::self()->startThreadPool();
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/IWeaver.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/IWeaver.aidl
index 29bd9a9..61627d9 100644
--- a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/IWeaver.aidl
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/IWeaver.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -37,6 +38,6 @@
   android.hardware.weaver.WeaverReadResponse read(in int slotId, in byte[] key);
   void write(in int slotId, in byte[] key, in byte[] value);
   const int STATUS_FAILED = 1;
-  const int INCORRECT_KEY = 2;
-  const int THROTTLE = 3;
+  const int STATUS_INCORRECT_KEY = 2;
+  const int STATUS_THROTTLE = 3;
 }
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverConfig.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverConfig.aidl
index 239cdac..7491f32 100644
--- a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverConfig.aidl
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverConfig.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -33,7 +34,7 @@
 package android.hardware.weaver;
 @VintfStability
 parcelable WeaverConfig {
-  long slots;
-  long keySize;
-  long valueSize;
+  int slots;
+  int keySize;
+  int valueSize;
 }
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
index 7e5db59..47ee4c8 100644
--- a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
@@ -12,7 +12,8 @@
  * 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.                          //
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/weaver/aidl/android/hardware/weaver/IWeaver.aidl b/weaver/aidl/android/hardware/weaver/IWeaver.aidl
index ebbfabe..f51034a 100644
--- a/weaver/aidl/android/hardware/weaver/IWeaver.aidl
+++ b/weaver/aidl/android/hardware/weaver/IWeaver.aidl
@@ -46,8 +46,8 @@
      * Read binder calls may return a ServiceSpecificException with the following error codes.
      */
     const int STATUS_FAILED = 1;
-    const int INCORRECT_KEY = 2;
-    const int THROTTLE = 3;
+    const int STATUS_INCORRECT_KEY = 2;
+    const int STATUS_THROTTLE = 3;
 
     /**
      * Attempts to retrieve the value stored in the identified slot.
diff --git a/weaver/aidl/android/hardware/weaver/WeaverConfig.aidl b/weaver/aidl/android/hardware/weaver/WeaverConfig.aidl
index 75d961e..a156a7b 100644
--- a/weaver/aidl/android/hardware/weaver/WeaverConfig.aidl
+++ b/weaver/aidl/android/hardware/weaver/WeaverConfig.aidl
@@ -21,14 +21,14 @@
     /**
      * The number of slots available.
      */
-    long slots;
+    int slots;
     /**
      * The number of bytes used for a key.
      */
-    long keySize;
+    int keySize;
     /**
      * The number of bytes used for a value.
      */
-    long valueSize;
+    int valueSize;
 }
 
diff --git a/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp b/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp
index 7d8daa2..878c762 100644
--- a/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp
+++ b/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp
@@ -156,7 +156,7 @@
 
     ASSERT_FALSE(readRet.isOk());
     ASSERT_EQ(EX_SERVICE_SPECIFIC, readRet.getExceptionCode());
-    ASSERT_EQ(IWeaver::INCORRECT_KEY, readRet.getServiceSpecificError());
+    ASSERT_EQ(IWeaver::STATUS_INCORRECT_KEY, readRet.getServiceSpecificError());
     EXPECT_TRUE(readValue.empty());
 }
 
diff --git a/wifi/1.0/vts/OWNERS b/wifi/1.0/vts/OWNERS
index 8bfb148..e7b2fc5 100644
--- a/wifi/1.0/vts/OWNERS
+++ b/wifi/1.0/vts/OWNERS
@@ -1,2 +1,2 @@
-rpius@google.com
+kumaranand@google.com
 etancohen@google.com
diff --git a/wifi/1.1/vts/OWNERS b/wifi/1.1/vts/OWNERS
index 8bfb148..e7b2fc5 100644
--- a/wifi/1.1/vts/OWNERS
+++ b/wifi/1.1/vts/OWNERS
@@ -1,2 +1,2 @@
-rpius@google.com
+kumaranand@google.com
 etancohen@google.com
diff --git a/wifi/1.2/vts/OWNERS b/wifi/1.2/vts/OWNERS
index 8bfb148..e7b2fc5 100644
--- a/wifi/1.2/vts/OWNERS
+++ b/wifi/1.2/vts/OWNERS
@@ -1,2 +1,2 @@
-rpius@google.com
+kumaranand@google.com
 etancohen@google.com
diff --git a/wifi/1.3/vts/OWNERS b/wifi/1.3/vts/OWNERS
index 8bfb148..e7b2fc5 100644
--- a/wifi/1.3/vts/OWNERS
+++ b/wifi/1.3/vts/OWNERS
@@ -1,2 +1,2 @@
-rpius@google.com
+kumaranand@google.com
 etancohen@google.com
diff --git a/wifi/1.4/vts/OWNERS b/wifi/1.4/vts/OWNERS
index 8bfb148..e7b2fc5 100644
--- a/wifi/1.4/vts/OWNERS
+++ b/wifi/1.4/vts/OWNERS
@@ -1,2 +1,2 @@
-rpius@google.com
+kumaranand@google.com
 etancohen@google.com
diff --git a/wifi/1.5/Android.bp b/wifi/1.5/Android.bp
index 7c04c69..0887c6b 100644
--- a/wifi/1.5/Android.bp
+++ b/wifi/1.5/Android.bp
@@ -20,6 +20,7 @@
         "IWifiNanIface.hal",
         "IWifiNanIfaceEventCallback.hal",
         "IWifiStaIface.hal",
+        "IWifiEventCallback.hal",
     ],
     interfaces: [
         "android.hardware.wifi@1.0",
diff --git a/wifi/1.5/IWifi.hal b/wifi/1.5/IWifi.hal
index 66d0a9c..28b808e 100644
--- a/wifi/1.5/IWifi.hal
+++ b/wifi/1.5/IWifi.hal
@@ -17,6 +17,8 @@
 package android.hardware.wifi@1.5;
 
 import @1.4::IWifi;
+import IWifiEventCallback;
+import @1.0::WifiStatus;
 
 /**
  * This is the root of the HAL module and is the interface returned when
@@ -24,4 +26,21 @@
  * module loaded in the system.
  * IWifi.getChip() must return @1.5::IWifiChip
  */
-interface IWifi extends @1.4::IWifi {};
+interface IWifi extends @1.4::IWifi {
+  /**
+   * Requests notifications of significant events for the HAL. Multiple calls to
+   * this must register multiple callbacks each of which must receive all
+   * events. |IWifiEventCallback| object registration must be independent of the
+   * state of the rest of the HAL and must persist though stops/starts. These
+   * objects must be deleted when the corresponding client process is dead.
+   *
+   * @param callback An instance of the |IWifiEventCallback| HIDL interface
+   *        object.
+   * @return status WifiStatus of the operation.
+   *         Possible status codes:
+   *         |WifiStatusCode.SUCCESS|,
+   *         |WifiStatusCode.UNKNOWN|
+   */
+  registerEventCallback_1_5(IWifiEventCallback callback)
+      generates (WifiStatus status);
+};
diff --git a/wifi/1.5/IWifiChip.hal b/wifi/1.5/IWifiChip.hal
index 5a3e288..8d7a36e 100644
--- a/wifi/1.5/IWifiChip.hal
+++ b/wifi/1.5/IWifiChip.hal
@@ -47,6 +47,15 @@
      *   - This will be invoked before an active wifi connection is established on the second
      *     interface.
      *   - This use-case hint is implicitly void when the second STA interface is brought down.
+     *   - When there is only 1 STA interface, the must should still retain the last use case
+     *     set, which must become active the next time multi STA is enabled.
+     *     1. Initialize with single STA.
+     *     2. Framework creates second STA.
+     *     3. Framework sets use case to DUAL_STA_NON_TRANSIENT_UNBIASED.
+     *     4. Framework destroys second STA. Only 1 STA remains.
+     *     5. Framework recreates second STA.
+     *     6. The active use case remains DUAL_STA_NON_TRANSIENT_UNBIASED (i.e. firmware should not
+     *        automatically change it during period of single STA unless requested by framework).
      */
     enum MultiStaUseCase : uint8_t {
         /**
@@ -100,11 +109,14 @@
     /**
      * Invoked to indicate that the provided iface is the primary STA iface when there are more
      * than 1 STA iface concurrently active.
-     * Note: If the wifi firmware/chip cannot support multiple instances of any offload
-     * (like roaming, APF, rssi threshold, etc), the firmware should ensure that these
-     * offloads are at least enabled for the primary interface. If the new primary interface is
-     * already connected to a network, the firmware must switch all the offloads on
-     * this new interface without disconnecting.
+     * Notes:
+     * - If the wifi firmware/chip cannot support multiple instances of any offload
+     *   (like roaming, APF, rssi threshold, etc), the firmware should ensure that these
+     *   offloads are at least enabled for the primary interface. If the new primary interface is
+     *   already connected to a network, the firmware must switch all the offloads on
+     *   this new interface without disconnecting.
+     * - When there is only 1 STA interface, the firmware must still retain the last primary
+     *   connection, which must become active the next time multi STA is enabled.
      *
      * @param ifname Name of the STA iface.
      * @return status WifiStatus of the operation.
@@ -303,4 +315,25 @@
     getUsableChannels(WifiBand band, bitfield<WifiIfaceMode> ifaceModeMask,
             bitfield<UsableChannelFilter> filterMask)
         generates (WifiStatus status, vec<WifiUsableChannel> channels);
+
+    /**
+     * Trigger subsystem restart
+     *
+     * If the framework detects a problem (e.g. connection failure),
+     * it must call this function to attempt recovery.
+     *
+     * When the wifi HAL receiveds triggerSubsystemRestart(), it must restart
+     * the wlan subsystem, especially the wlan firmware.
+     *
+     * Regarding the callback function for subsystem restart, refer to documentation of
+     * |IWifiEventCallback.onSubsystemRestart| for details.
+     *
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    triggerSubsystemRestart() generates (WifiStatus status);
 };
diff --git a/wifi/1.5/IWifiEventCallback.hal b/wifi/1.5/IWifiEventCallback.hal
new file mode 100644
index 0000000..ff27630
--- /dev/null
+++ b/wifi/1.5/IWifiEventCallback.hal
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi@1.5;
+
+import @1.0::IWifiEventCallback;
+import @1.0::WifiStatus;
+
+interface IWifiEventCallback extends @1.0::IWifiEventCallback {
+  /**
+    * Must be called when the Wi-Fi subsystem restart completes.
+    * Once this event is received, framework must fully reset the Wi-Fi stack state.
+    */
+  oneway onSubsystemRestart(WifiStatus status);
+};
diff --git a/wifi/1.5/default/OWNERS b/wifi/1.5/default/OWNERS
index 8bfb148..e7b2fc5 100644
--- a/wifi/1.5/default/OWNERS
+++ b/wifi/1.5/default/OWNERS
@@ -1,2 +1,2 @@
-rpius@google.com
+kumaranand@google.com
 etancohen@google.com
diff --git a/wifi/1.5/default/hidl_struct_util.cpp b/wifi/1.5/default/hidl_struct_util.cpp
index 125a50f..338a8f1 100644
--- a/wifi/1.5/default/hidl_struct_util.cpp
+++ b/wifi/1.5/default/hidl_struct_util.cpp
@@ -954,27 +954,29 @@
 
 bool convertLegacyLinkLayerRadioStatsToHidl(
     const legacy_hal::LinkLayerRadioStats& legacy_radio_stat,
-    V1_3::StaLinkLayerRadioStats* hidl_radio_stat) {
+    V1_5::StaLinkLayerRadioStats* hidl_radio_stat) {
     if (!hidl_radio_stat) {
         return false;
     }
     *hidl_radio_stat = {};
 
-    hidl_radio_stat->V1_0.onTimeInMs = legacy_radio_stat.stats.on_time;
-    hidl_radio_stat->V1_0.txTimeInMs = legacy_radio_stat.stats.tx_time;
-    hidl_radio_stat->V1_0.rxTimeInMs = legacy_radio_stat.stats.rx_time;
-    hidl_radio_stat->V1_0.onTimeInMsForScan =
+    hidl_radio_stat->radioId = legacy_radio_stat.stats.radio;
+    hidl_radio_stat->V1_3.V1_0.onTimeInMs = legacy_radio_stat.stats.on_time;
+    hidl_radio_stat->V1_3.V1_0.txTimeInMs = legacy_radio_stat.stats.tx_time;
+    hidl_radio_stat->V1_3.V1_0.rxTimeInMs = legacy_radio_stat.stats.rx_time;
+    hidl_radio_stat->V1_3.V1_0.onTimeInMsForScan =
         legacy_radio_stat.stats.on_time_scan;
-    hidl_radio_stat->V1_0.txTimeInMsPerLevel =
+    hidl_radio_stat->V1_3.V1_0.txTimeInMsPerLevel =
         legacy_radio_stat.tx_time_per_levels;
-    hidl_radio_stat->onTimeInMsForNanScan = legacy_radio_stat.stats.on_time_nbd;
-    hidl_radio_stat->onTimeInMsForBgScan =
+    hidl_radio_stat->V1_3.onTimeInMsForNanScan =
+        legacy_radio_stat.stats.on_time_nbd;
+    hidl_radio_stat->V1_3.onTimeInMsForBgScan =
         legacy_radio_stat.stats.on_time_gscan;
-    hidl_radio_stat->onTimeInMsForRoamScan =
+    hidl_radio_stat->V1_3.onTimeInMsForRoamScan =
         legacy_radio_stat.stats.on_time_roam_scan;
-    hidl_radio_stat->onTimeInMsForPnoScan =
+    hidl_radio_stat->V1_3.onTimeInMsForPnoScan =
         legacy_radio_stat.stats.on_time_pno_scan;
-    hidl_radio_stat->onTimeInMsForHs20Scan =
+    hidl_radio_stat->V1_3.onTimeInMsForHs20Scan =
         legacy_radio_stat.stats.on_time_hs20;
 
     std::vector<V1_3::WifiChannelStats> hidl_channel_stats;
@@ -996,7 +998,7 @@
         hidl_channel_stats.push_back(hidl_channel_stat);
     }
 
-    hidl_radio_stat->channelStats = hidl_channel_stats;
+    hidl_radio_stat->V1_3.channelStats = hidl_channel_stats;
 
     return true;
 }
@@ -1089,9 +1091,9 @@
     }
     hidl_stats->iface.peers = hidl_peers_info_stats;
     // radio legacy_stats conversion.
-    std::vector<V1_3::StaLinkLayerRadioStats> hidl_radios_stats;
+    std::vector<V1_5::StaLinkLayerRadioStats> hidl_radios_stats;
     for (const auto& legacy_radio_stats : legacy_stats.radios) {
-        V1_3::StaLinkLayerRadioStats hidl_radio_stats;
+        V1_5::StaLinkLayerRadioStats hidl_radio_stats;
         if (!convertLegacyLinkLayerRadioStatsToHidl(legacy_radio_stats,
                                                     &hidl_radio_stats)) {
             return false;
diff --git a/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
index e70d7ba..4b4ebd6 100644
--- a/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
+++ b/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
@@ -180,6 +180,7 @@
     legacy_stats.iface.num_peers = 1;
 
     for (auto& radio : legacy_stats.radios) {
+        radio.stats.radio = rand();
         radio.stats.on_time = rand();
         radio.stats.tx_time = rand();
         radio.stats.rx_time = rand();
@@ -314,48 +315,53 @@
 
     EXPECT_EQ(legacy_stats.radios.size(), converted.radios.size());
     for (size_t i = 0; i < legacy_stats.radios.size(); i++) {
+        EXPECT_EQ(legacy_stats.radios[i].stats.radio,
+                  converted.radios[i].radioId);
         EXPECT_EQ(legacy_stats.radios[i].stats.on_time,
-                  converted.radios[i].V1_0.onTimeInMs);
+                  converted.radios[i].V1_3.V1_0.onTimeInMs);
         EXPECT_EQ(legacy_stats.radios[i].stats.tx_time,
-                  converted.radios[i].V1_0.txTimeInMs);
+                  converted.radios[i].V1_3.V1_0.txTimeInMs);
         EXPECT_EQ(legacy_stats.radios[i].stats.rx_time,
-                  converted.radios[i].V1_0.rxTimeInMs);
+                  converted.radios[i].V1_3.V1_0.rxTimeInMs);
         EXPECT_EQ(legacy_stats.radios[i].stats.on_time_scan,
-                  converted.radios[i].V1_0.onTimeInMsForScan);
+                  converted.radios[i].V1_3.V1_0.onTimeInMsForScan);
         EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels.size(),
-                  converted.radios[i].V1_0.txTimeInMsPerLevel.size());
+                  converted.radios[i].V1_3.V1_0.txTimeInMsPerLevel.size());
         for (size_t j = 0; j < legacy_stats.radios[i].tx_time_per_levels.size();
              j++) {
             EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels[j],
-                      converted.radios[i].V1_0.txTimeInMsPerLevel[j]);
+                      converted.radios[i].V1_3.V1_0.txTimeInMsPerLevel[j]);
         }
         EXPECT_EQ(legacy_stats.radios[i].stats.on_time_nbd,
-                  converted.radios[i].onTimeInMsForNanScan);
+                  converted.radios[i].V1_3.onTimeInMsForNanScan);
         EXPECT_EQ(legacy_stats.radios[i].stats.on_time_gscan,
-                  converted.radios[i].onTimeInMsForBgScan);
+                  converted.radios[i].V1_3.onTimeInMsForBgScan);
         EXPECT_EQ(legacy_stats.radios[i].stats.on_time_roam_scan,
-                  converted.radios[i].onTimeInMsForRoamScan);
+                  converted.radios[i].V1_3.onTimeInMsForRoamScan);
         EXPECT_EQ(legacy_stats.radios[i].stats.on_time_pno_scan,
-                  converted.radios[i].onTimeInMsForPnoScan);
+                  converted.radios[i].V1_3.onTimeInMsForPnoScan);
         EXPECT_EQ(legacy_stats.radios[i].stats.on_time_hs20,
-                  converted.radios[i].onTimeInMsForHs20Scan);
+                  converted.radios[i].V1_3.onTimeInMsForHs20Scan);
         EXPECT_EQ(legacy_stats.radios[i].channel_stats.size(),
-                  converted.radios[i].channelStats.size());
+                  converted.radios[i].V1_3.channelStats.size());
         for (size_t k = 0; k < legacy_stats.radios[i].channel_stats.size();
              k++) {
             auto& legacy_channel_st = legacy_stats.radios[i].channel_stats[k];
             EXPECT_EQ(WifiChannelWidthInMhz::WIDTH_20,
-                      converted.radios[i].channelStats[k].channel.width);
-            EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq),
-                      converted.radios[i].channelStats[k].channel.centerFreq);
-            EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq0),
-                      converted.radios[i].channelStats[k].channel.centerFreq0);
-            EXPECT_EQ(WifiChannelInMhz(legacy_channel_st.channel.center_freq1),
-                      converted.radios[i].channelStats[k].channel.centerFreq1);
+                      converted.radios[i].V1_3.channelStats[k].channel.width);
+            EXPECT_EQ(
+                WifiChannelInMhz(legacy_channel_st.channel.center_freq),
+                converted.radios[i].V1_3.channelStats[k].channel.centerFreq);
+            EXPECT_EQ(
+                WifiChannelInMhz(legacy_channel_st.channel.center_freq0),
+                converted.radios[i].V1_3.channelStats[k].channel.centerFreq0);
+            EXPECT_EQ(
+                WifiChannelInMhz(legacy_channel_st.channel.center_freq1),
+                converted.radios[i].V1_3.channelStats[k].channel.centerFreq1);
             EXPECT_EQ(legacy_channel_st.cca_busy_time,
-                      converted.radios[i].channelStats[k].ccaBusyTimeInMs);
+                      converted.radios[i].V1_3.channelStats[k].ccaBusyTimeInMs);
             EXPECT_EQ(legacy_channel_st.on_time,
-                      converted.radios[i].channelStats[k].onTimeInMs);
+                      converted.radios[i].V1_3.channelStats[k].onTimeInMs);
         }
     }
 
diff --git a/wifi/1.5/default/wifi.cpp b/wifi/1.5/default/wifi.cpp
index da98db8..b9f20a4 100644
--- a/wifi/1.5/default/wifi.cpp
+++ b/wifi/1.5/default/wifi.cpp
@@ -50,13 +50,21 @@
 }
 
 Return<void> Wifi::registerEventCallback(
-    const sp<IWifiEventCallback>& event_callback,
+    const sp<V1_0::IWifiEventCallback>& event_callback,
     registerEventCallback_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
                            &Wifi::registerEventCallbackInternal, hidl_status_cb,
                            event_callback);
 }
 
+Return<void> Wifi::registerEventCallback_1_5(
+    const sp<V1_5::IWifiEventCallback>& event_callback,
+    registerEventCallback_1_5_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+                           &Wifi::registerEventCallbackInternal_1_5,
+                           hidl_status_cb, event_callback);
+}
+
 Return<bool> Wifi::isStarted() { return run_state_ != RunState::STOPPED; }
 
 Return<void> Wifi::start(start_cb hidl_status_cb) {
@@ -95,7 +103,13 @@
 }
 
 WifiStatus Wifi::registerEventCallbackInternal(
-    const sp<IWifiEventCallback>& event_callback) {
+    const sp<V1_0::IWifiEventCallback>& event_callback __unused) {
+    // Deprecated support for this callback.
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus Wifi::registerEventCallbackInternal_1_5(
+    const sp<V1_5::IWifiEventCallback>& event_callback) {
     if (!event_cb_handler_.addCallback(event_callback)) {
         return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
     }
@@ -117,7 +131,7 @@
                 WifiStatus wifi_status =
                     createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, error);
                 for (const auto& callback : event_cb_handler_.getCallbacks()) {
-                    if (!callback->onFailure(wifi_status).isOk()) {
+                    if (!callback->onSubsystemRestart(wifi_status).isOk()) {
                         LOG(ERROR) << "Failed to invoke onFailure callback";
                     }
                 }
diff --git a/wifi/1.5/default/wifi.h b/wifi/1.5/default/wifi.h
index 825c0bc..840bdfd 100644
--- a/wifi/1.5/default/wifi.h
+++ b/wifi/1.5/default/wifi.h
@@ -52,8 +52,11 @@
 
     // HIDL methods exposed.
     Return<void> registerEventCallback(
-        const sp<IWifiEventCallback>& event_callback,
+        const sp<V1_0::IWifiEventCallback>& event_callback,
         registerEventCallback_cb hidl_status_cb) override;
+    Return<void> registerEventCallback_1_5(
+        const sp<V1_5::IWifiEventCallback>& event_callback,
+        registerEventCallback_1_5_cb hidl_status_cb) override;
     Return<bool> isStarted() override;
     Return<void> start(start_cb hidl_status_cb) override;
     Return<void> stop(stop_cb hidl_status_cb) override;
@@ -67,7 +70,9 @@
 
     // Corresponding worker functions for the HIDL methods.
     WifiStatus registerEventCallbackInternal(
-        const sp<IWifiEventCallback>& event_callback);
+        const sp<V1_0::IWifiEventCallback>& event_callback __unused);
+    WifiStatus registerEventCallbackInternal_1_5(
+        const sp<V1_5::IWifiEventCallback>& event_callback);
     WifiStatus startInternal();
     WifiStatus stopInternal(std::unique_lock<std::recursive_mutex>* lock);
     std::pair<WifiStatus, std::vector<ChipId>> getChipIdsInternal();
@@ -87,7 +92,7 @@
     std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
     RunState run_state_;
     std::vector<sp<WifiChip>> chips_;
-    hidl_callback_util::HidlCallbackHandler<IWifiEventCallback>
+    hidl_callback_util::HidlCallbackHandler<V1_5::IWifiEventCallback>
         event_cb_handler_;
 
     DISALLOW_COPY_AND_ASSIGN(Wifi);
diff --git a/wifi/1.5/default/wifi_chip.cpp b/wifi/1.5/default/wifi_chip.cpp
index 0499f45..961f9da 100644
--- a/wifi/1.5/default/wifi_chip.cpp
+++ b/wifi/1.5/default/wifi_chip.cpp
@@ -747,6 +747,13 @@
                            ifaceModeMask, filterMask);
 }
 
+Return<void> WifiChip::triggerSubsystemRestart(
+    triggerSubsystemRestart_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::triggerSubsystemRestartInternal,
+                           hidl_status_cb);
+}
+
 void WifiChip::invalidateAndRemoveAllIfaces() {
     invalidateAndClearBridgedApAll();
     invalidateAndClearAll(ap_ifaces_);
@@ -1522,6 +1529,11 @@
     return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_usable_channels};
 }
 
+WifiStatus WifiChip::triggerSubsystemRestartInternal() {
+    auto legacy_status = legacy_hal_.lock()->triggerSubsystemRestart();
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
 WifiStatus WifiChip::handleChipConfiguration(
     /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
     ChipModeId mode_id) {
diff --git a/wifi/1.5/default/wifi_chip.h b/wifi/1.5/default/wifi_chip.h
index 92d639f..bd40ead 100644
--- a/wifi/1.5/default/wifi_chip.h
+++ b/wifi/1.5/default/wifi_chip.h
@@ -184,6 +184,8 @@
         WifiBand band, hidl_bitfield<WifiIfaceMode> ifaceModeMask,
         hidl_bitfield<UsableChannelFilter> filterMask,
         getUsableChannels_cb _hidl_cb) override;
+    Return<void> triggerSubsystemRestart(
+        triggerSubsystemRestart_cb hidl_status_cb) override;
 
    private:
     void invalidateAndRemoveAllIfaces();
@@ -303,6 +305,7 @@
     void invalidateAndClearBridgedApAll();
     void invalidateAndClearBridgedAp(const std::string& br_name);
     bool findUsingNameFromBridgedApInstances(const std::string& name);
+    WifiStatus triggerSubsystemRestartInternal();
 
     ChipId chip_id_;
     std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
diff --git a/wifi/1.5/default/wifi_legacy_hal.cpp b/wifi/1.5/default/wifi_legacy_hal.cpp
index 45ad84b..5074252 100644
--- a/wifi/1.5/default/wifi_legacy_hal.cpp
+++ b/wifi/1.5/default/wifi_legacy_hal.cpp
@@ -1676,6 +1676,10 @@
     return {status, std::move(channels)};
 }
 
+wifi_error WifiLegacyHal::triggerSubsystemRestart() {
+    return global_func_table_.wifi_trigger_subsystem_restart(global_handle_);
+}
+
 void WifiLegacyHal::invalidate() {
     global_handle_ = nullptr;
     iface_name_to_handle_.clear();
diff --git a/wifi/1.5/default/wifi_legacy_hal.h b/wifi/1.5/default/wifi_legacy_hal.h
index 8ebc66a..2bb7631 100644
--- a/wifi/1.5/default/wifi_legacy_hal.h
+++ b/wifi/1.5/default/wifi_legacy_hal.h
@@ -716,6 +716,8 @@
     std::pair<wifi_error, std::vector<wifi_usable_channel>> getUsableChannels(
         uint32_t band_mask, uint32_t iface_mode_mask, uint32_t filter_mask);
 
+    wifi_error triggerSubsystemRestart();
+
    private:
     // Retrieve interface handles for all the available interfaces.
     wifi_error retrieveIfaceHandles();
diff --git a/wifi/1.5/default/wifi_legacy_hal_stubs.cpp b/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
index 6212960..dd860d6 100644
--- a/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
@@ -160,6 +160,7 @@
     populateStubFor(&hal_fn->wifi_twt_clear_stats);
     populateStubFor(&hal_fn->wifi_set_dtim_config);
     populateStubFor(&hal_fn->wifi_get_usable_channels);
+    populateStubFor(&hal_fn->wifi_trigger_subsystem_restart);
     return true;
 }
 }  // namespace legacy_hal
diff --git a/wifi/1.5/types.hal b/wifi/1.5/types.hal
index 0543004..3c19791 100644
--- a/wifi/1.5/types.hal
+++ b/wifi/1.5/types.hal
@@ -253,6 +253,21 @@
     vec<StaPeerInfo> peers;
 };
 
+struct StaLinkLayerRadioStats {
+    /**
+     * Baseline information as defined in HAL 1.3.
+     */
+    @1.3::StaLinkLayerRadioStats V1_3;
+
+    /**
+     * Radio ID: An implementation specific value identifying the radio interface for which the
+     * stats are produced. Framework must not interpret this value. It must use this value for
+     * persistently identifying the statistics between calls,
+     * e.g. if the HAL provides them in different order.
+     */
+    int32_t radioId;
+};
+
 /**
  * Link layer stats retrieved via |getLinkLayerStats|.
  */
diff --git a/wifi/1.5/vts/OWNERS b/wifi/1.5/vts/OWNERS
index 8bfb148..e7b2fc5 100644
--- a/wifi/1.5/vts/OWNERS
+++ b/wifi/1.5/vts/OWNERS
@@ -1,2 +1,2 @@
-rpius@google.com
+kumaranand@google.com
 etancohen@google.com
diff --git a/wifi/hostapd/1.0/vts/OWNERS b/wifi/hostapd/1.0/vts/OWNERS
index 8bfb148..e7b2fc5 100644
--- a/wifi/hostapd/1.0/vts/OWNERS
+++ b/wifi/hostapd/1.0/vts/OWNERS
@@ -1,2 +1,2 @@
-rpius@google.com
+kumaranand@google.com
 etancohen@google.com
diff --git a/wifi/hostapd/1.1/vts/OWNERS b/wifi/hostapd/1.1/vts/OWNERS
index 8bfb148..e7b2fc5 100644
--- a/wifi/hostapd/1.1/vts/OWNERS
+++ b/wifi/hostapd/1.1/vts/OWNERS
@@ -1,2 +1,2 @@
-rpius@google.com
+kumaranand@google.com
 etancohen@google.com
diff --git a/wifi/hostapd/1.2/vts/OWNERS b/wifi/hostapd/1.2/vts/OWNERS
index 8bfb148..e7b2fc5 100644
--- a/wifi/hostapd/1.2/vts/OWNERS
+++ b/wifi/hostapd/1.2/vts/OWNERS
@@ -1,2 +1,2 @@
-rpius@google.com
+kumaranand@google.com
 etancohen@google.com
diff --git a/wifi/hostapd/1.3/types.hal b/wifi/hostapd/1.3/types.hal
index f453df7..2230da8 100644
--- a/wifi/hostapd/1.3/types.hal
+++ b/wifi/hostapd/1.3/types.hal
@@ -25,7 +25,7 @@
  * WIFI_STANDARD_11N = [hw_mode is HOSTAPD_MODE_IEEE80211G and (HT is 1 or HT40 is 1)] or
  *                     [hw_mode is HOSTAPD_MODE_IEEE80211A and VHT is 0].
  * WIFI_STANDARD_11AC = hw_mode is HOSTAPD_MODE_IEEE80211A and VHT is 1.
- * WIFI_STANDARD_11AX = hw_mode is HOSTAPD_MODE_IEEE80211AX.
+ * WIFI_STANDARD_11AX = hw_mode is HOSTAPD_MODE_IEEE80211A and HE supported.
  * WIFI_STANDARD_11AD = hw_mode is HOSTAPD_MODE_IEEE80211AD.
  */
 enum Generation : uint32_t {
diff --git a/wifi/hostapd/1.3/vts/OWNERS b/wifi/hostapd/1.3/vts/OWNERS
index 8bfb148..e7b2fc5 100644
--- a/wifi/hostapd/1.3/vts/OWNERS
+++ b/wifi/hostapd/1.3/vts/OWNERS
@@ -1,2 +1,2 @@
-rpius@google.com
+kumaranand@google.com
 etancohen@google.com
diff --git a/wifi/supplicant/1.2/vts/OWNERS b/wifi/supplicant/1.2/vts/OWNERS
index 8bfb148..e7b2fc5 100644
--- a/wifi/supplicant/1.2/vts/OWNERS
+++ b/wifi/supplicant/1.2/vts/OWNERS
@@ -1,2 +1,2 @@
-rpius@google.com
+kumaranand@google.com
 etancohen@google.com
diff --git a/wifi/supplicant/1.3/vts/OWNERS b/wifi/supplicant/1.3/vts/OWNERS
index 8bfb148..e7b2fc5 100644
--- a/wifi/supplicant/1.3/vts/OWNERS
+++ b/wifi/supplicant/1.3/vts/OWNERS
@@ -1,2 +1,2 @@
-rpius@google.com
+kumaranand@google.com
 etancohen@google.com
diff --git a/wifi/supplicant/1.4/ISupplicantStaNetwork.hal b/wifi/supplicant/1.4/ISupplicantStaNetwork.hal
index 4f95213..4dfe8e6 100644
--- a/wifi/supplicant/1.4/ISupplicantStaNetwork.hal
+++ b/wifi/supplicant/1.4/ISupplicantStaNetwork.hal
@@ -41,7 +41,7 @@
         /**
          * GCMP-128 Pairwise Cipher
          */
-        GCMP_128 = 1 << 9,
+        GCMP_128 = 1 << 6,
     };
 
     /**
@@ -51,7 +51,7 @@
         /**
          * GCMP-128 Group Cipher
          */
-        GCMP_128 = 1 << 9,
+        GCMP_128 = 1 << 6,
     };
 
     /**
diff --git a/wifi/supplicant/1.4/vts/OWNERS b/wifi/supplicant/1.4/vts/OWNERS
index 8bfb148..e7b2fc5 100644
--- a/wifi/supplicant/1.4/vts/OWNERS
+++ b/wifi/supplicant/1.4/vts/OWNERS
@@ -1,2 +1,2 @@
-rpius@google.com
+kumaranand@google.com
 etancohen@google.com